feat: add bulk modification support for calendar groups#26
Merged
hugobessa merged 1 commit intofeat/calendar-groups-and-slotsfrom Apr 27, 2026
Merged
Conversation
5b80386 to
a580f72
Compare
ad1d220 to
6ad6d52
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/calendar-groups-and-slots-pt5 #26 +/- ##
======================================================================
+ Coverage 81.54% 81.61% +0.06%
======================================================================
Files 157 157
Lines 9994 10085 +91
Branches 1080 1101 +21
======================================================================
+ Hits 8150 8231 +81
- Misses 1406 1411 +5
- Partials 438 443 +5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 6 — CalendarGroup follow-ups: permission delegation, bulk-modification parity, batched
find_bookable_slotsSummary
Closes out three of the four follow-ups queued for PR 6 in dev-plans/2026-04-20-CALENDAR_GROUP_PLAN.md. Each item is small and independent enough to ship alongside the others without stepping on anything that came before. Option A (bundle-based persistence for non-primary selections) remains deferred — the plan recommends holding on it unless Option B proves insufficient in production.
What's in
CalendarPermissionService.can_manage_calendar_group+CalendarGroupPermissiondelegates to it.*_with_bulk_modificationsparity forCalendarandCalendarGroupquerysets, plus the corresponding flag onCalendarGroupService.check_group_availability.find_bookable_slots— replaces the per-candidate DB round-trip with a precomputed in-memory scan.What's deferred
can_manage_calendar_group— blocked on a prerequisite (no org-admin role exists onOrganizationMembershiptoday). Docstring flags where the override would slot in.Details
1.
can_manage_calendar_groupNew method on
CalendarPermissionService:CalendarGroupPermissionnow injects the service via DI and delegateshas_object_permissionto it, so the manage-group rule has a single implementation. A safe fallback path preserves the inline ownership query if DI ever fails to wire, so tests and scripts that instantiate the permission directly still work.2.
*_with_bulk_modificationsparityCalendarQuerySetandCalendarGroupQuerySeteach gained a_with_bulk_modificationsvariant sharing the existing implementation via awith_bulk_modifications: boolhelper. The bulk-aware path swapsannotate_recurring_occurrences_on_date_rangeforannotate_recurring_occurrences_with_bulk_modifications_on_date_rangeon events, so continuation occurrences from bulk-modified recurring series count against availability.Exposed via:
Calendar.objects.only_calendars_available_in_ranges_with_bulk_modifications(ranges)CalendarGroup.objects.only_groups_bookable_in_ranges_with_bulk_modifications(ranges)CalendarGroupService.check_group_availability(..., with_bulk_modifications=True)3. Batched
find_bookable_slotsCalendarGroupService.find_bookable_slotswas a Python loop that issued one availability query per candidate window. A 6-hour search at a 15-minute step made 24 round-trips for a read-only operation.The new implementation:
required_countonce.AvailableTimespans (managed) andCalendarEvent+BlockedTimespans (unmanaged) once for the whole search window, with recurring-occurrence expansion.Also takes
with_bulk_modifications: bool = Falsefor parity withcheck_group_availability.Query-count delta for a 6-hour window at 15-min step (24 candidates):
A regression guard pins the bound with
django_assert_max_num_queries(8).Files touched
can_manage_calendar_group.CalendarGroupPermissiondelegates via DI.only_calendars_available_in_ranges_with_bulk_modificationsandonly_groups_bookable_in_ranges_with_bulk_modifications.CalendarManager/CalendarGroupManager.find_bookable_slots;with_bulk_modificationsflag oncheck_group_availabilityandfind_bookable_slots.Test plan
only_groups_bookable_in_ranges_with_bulk_modificationssmoke test (no bulk mods → same result as non-bulk variant).check_group_availability(with_bulk_modifications=True)returns the same per-slot availability when no bulk modifications exist.find_bookable_slotsmatches prior behavior in the all-available happy path.find_bookable_slotsexcludes candidate windows overlapping an unmanaged calendar's blocking event.find_bookable_slotsreturns[]when any slot pool is empty.find_bookable_slotsover 24 candidates issues<=8queries.can_manage_calendar_group: true for an owner of any pool calendar, false for strangers, scoped to the group's organization.CalendarGroupPermissiondelegates toCalendarPermissionService.can_manage_calendar_groupwhen DI is wired, and falls back cleanly when it isn't.calendar_integration/tests/+public_api/tests/suites pass — 905 tests (up from 894).Rollout notes
with_bulk_modificationsflag defaults toFalse, so existing call-sites are unaffected.CalendarGroupPermissioncallers that construct the class directly (outside DI) keep working via the documented fallback path.Follow-ups
OrganizationMembership— once introduced, extendcan_manage_calendar_groupwith an admin override (single call-site change).