Put schedule_interview and a read-only view of the calendar's other dated things on the plugin surface #330
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#330
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
For interviews,
postulo.plugins.apioffersInterviewandInterviewOutcome,reschedule_interviewandsettle_interview(each with an actor), and the calendar textevent_linesandcalendar_status. That was enough for postulo-dav to push interviews and pull edits to them. It is not enough for what the plugin is now asked to do, pair an event made elsewhere with an interview or another dated thing on Postulo (postulo/postulo-dav#11), in two places:schedule_interview(src/postulo/applications/services.py:378) is off the surface, and so isInterviewKind, the vocabulary it takes. It writes theinterview_scheduledentry, adds a reminder a day ahead, and records an interview that is already over as held (:410-411). A plugin cannot do the same: saving anInterviewskips all three, andReminderis off the surface too. Accepting a suggestion never creates an interview (applications/suggestions.py:69), sosuggestis no way round. The checks its callers make first (a known kind, the end after the start, contacts that are the owner's and at the application's company:api/routers/interviews.py:97-126,applications/forms.py:571-583) are not in the service.agenda.events_between(applications/agenda.py:197); the web feed writes the last three as whole days withDayEntryandday_lines(ical.py:202-245). None of these is on the surface, nor areOfferandJobPosting. A plugin can reach an application'sdeadline, and its listing'scloses_at, throughApplication; it cannot list the listings nobody has applied to, and it would have to restate which dates are over and what they are called.Proposal
schedule_interviewon the surface, with an actor, andInterviewKindbeside it. The checks the form and the API make move into the call, so a plugin cannot skip them: a kind that is anInterviewKind, an end after the start, and every contact the owner's and at the application's company, refused otherwise asrecord_listing_eventrefuses another person's contact (jobs/history.py:163-164).events_between, for a person and a range of days, answering plain values: kind, title, detail, the moment or the day, whether it is over, the absolute link, and for a whole day itsDayEntry, withday_lineson the surface to write it as the feed does. Reminder records and their services are #331.Each new name gets its line in both tables of the wiki's Writing a plugin (
tests/test_wiki_surface.py) and intests/test_plugin_surface.py(test_the_surface_holds_what_a_sync_needs), and the publishedpostulo.plugins.testingcheck passes a plugin using them. No page is added. No user-facing string is expected; any that appears goes in the working catalogues (en, fr-fr, pt-pt, pt-br as drafts).Decisions
event_linesneeds auid=. It always writesUID:{interview.uid}(applications/ical.py:172), at most 64 characters (applications/models.py:734), and CalDAV forbids changing an existing event's UID (RFC 4791 §5.3.2.1). But postulo/postulo-dav#11 recommends patching an event made elsewhere, never rebuilding it, and a plugin can take the lines it owns fromevent_linesand leave theUIDout. Recommend leavingevent_linesas it is. Alternative: a keyword-onlyuid=, if postulo/postulo-dav#11 settles on rebuilding paired events whole. Either way the remote UID stays on theSyncLink(200 characters), not inInterview.uid, which is unique per person while a UID is unique only per calendar (RFC 4791 §4.1).OfferandJobPostingon the surface:events_betweenis "the one place that decides what a deadline is" (applications/views.py:1059), so the page, the feed and a plugin cannot disagree.events_betweenbounds days in the active zone, and a scheduled sync activates none (plugins/syncing.py). Recommend the call reads in the person's zone, rather than leaving it to the caller.DayEntry.uidis a UUID over the entry's address, or its summary when it has none (ical.py:214-217). WithPOSTULO_PUBLIC_URLunset a scheduled job has only a path, and a UUID over a path is the collision between instances the module warns about. Recommend: with it unset, the call answers no whole days and says why. Alternative:day_linestakes a UID the plugin mints and keeps on the link.POSTULO_PUBLIC_URL, documented in the wiki's Configuration, from Django's settings and join it with a record'sget_absolute_url(). Alternative:absolute_url(notifications/base.py:154) on the surface, so the rule lives in one place.Needed by
Done when
From the list of DAV plugin improvements of 2026-09-30.
ATTENDEE, against the form's promise #963