Implement correlated campaign invitations
This commit is contained in:
@@ -12,6 +12,7 @@ from govoplan_calendar.backend.capabilities import (
|
||||
SqlCalendarInvitationProvider,
|
||||
SqlCalendarSchedulingProvider,
|
||||
)
|
||||
from govoplan_calendar.backend.db.models import CalendarEvent
|
||||
from govoplan_calendar.backend.schemas import CalendarCollectionCreateRequest
|
||||
from govoplan_calendar.backend.service import create_calendar
|
||||
from govoplan_core.core.calendar import (
|
||||
@@ -131,6 +132,10 @@ class CalendarInvitationCapabilityTests(unittest.TestCase):
|
||||
summary=summary,
|
||||
start_at=datetime(2026, 8, 5, 9, tzinfo=timezone.utc),
|
||||
end_at=datetime(2026, 8, 5, 10, tzinfo=timezone.utc),
|
||||
organizer={
|
||||
"value": "mailto:organizer@example.test",
|
||||
"params": {"CN": ["Organizer"]},
|
||||
},
|
||||
attendees=(
|
||||
CalendarInvitationAttendeeRequest(
|
||||
address="ada@example.test",
|
||||
@@ -173,6 +178,92 @@ class CalendarInvitationCapabilityTests(unittest.TestCase):
|
||||
self.assertFalse(updated.recurrence_supported)
|
||||
self.assertTrue(updated.degraded_reasons)
|
||||
|
||||
def test_invitation_render_batch_lookup_and_summary(self) -> None:
|
||||
request = self.request()
|
||||
payload = self.provider.render_invitation(request)
|
||||
created = self.provider.upsert_invitation(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
user_id=None,
|
||||
request=request,
|
||||
)
|
||||
|
||||
self.assertIn("METHOD:REQUEST", payload)
|
||||
self.assertIn(f"UID:{created.uid}", payload)
|
||||
self.assertEqual(
|
||||
created,
|
||||
self.provider.get_invitations(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
correlation_ids=(created.correlation_id,),
|
||||
)[created.correlation_id],
|
||||
)
|
||||
summary = self.provider.summarize_invitations(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
source_module="campaigns",
|
||||
source_resource_type="campaign_recipient",
|
||||
source_resource_id="recipient-1",
|
||||
)
|
||||
self.assertEqual(1, summary["invitation_count"])
|
||||
self.assertEqual(1, summary["pending_response_count"])
|
||||
calendars = self.provider.list_calendars(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
)
|
||||
self.assertEqual((self.calendar.id,), tuple(item.id for item in calendars))
|
||||
self.assertTrue(calendars[0].writable)
|
||||
|
||||
def test_icalendar_reply_updates_attendee_status(self) -> None:
|
||||
created = self.provider.upsert_invitation(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
user_id=None,
|
||||
request=self.request(),
|
||||
)
|
||||
reply = "\r\n".join(
|
||||
(
|
||||
"BEGIN:VCALENDAR",
|
||||
"VERSION:2.0",
|
||||
"METHOD:REPLY",
|
||||
"BEGIN:VEVENT",
|
||||
f"UID:{created.uid}",
|
||||
"DTSTART:20260805T090000Z",
|
||||
"ATTENDEE;CN=Ada;PARTSTAT=TENTATIVE:mailto:ada@example.test",
|
||||
"END:VEVENT",
|
||||
"END:VCALENDAR",
|
||||
"",
|
||||
)
|
||||
)
|
||||
|
||||
recorded = self.provider.record_icalendar_reply(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
icalendar=reply,
|
||||
evidence={"profile_id": "mail-profile-1", "uid": "42"},
|
||||
)
|
||||
sequence_after_first_reply = self.session.get(
|
||||
CalendarEvent,
|
||||
created.event_id,
|
||||
).sequence
|
||||
replayed = self.provider.record_icalendar_reply(
|
||||
self.session,
|
||||
tenant_id="tenant-1",
|
||||
icalendar=reply,
|
||||
evidence={"profile_id": "mail-profile-1", "uid": "42"},
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(recorded))
|
||||
self.assertEqual(1, len(replayed))
|
||||
self.assertEqual(
|
||||
"TENTATIVE",
|
||||
recorded[0].attendees[0]["params"]["PARTSTAT"][0],
|
||||
)
|
||||
self.assertEqual(
|
||||
sequence_after_first_reply,
|
||||
self.session.get(CalendarEvent, created.event_id).sequence,
|
||||
)
|
||||
|
||||
def test_reply_must_match_an_existing_attendee(self) -> None:
|
||||
created = self.provider.upsert_invitation(
|
||||
self.session,
|
||||
|
||||
Reference in New Issue
Block a user