Pair an event in a chosen calendar with an interview, make an interview from one, and stop an alarm's text replacing the notes #11

Open
opened 2026-09-30 20:30:03 +00:00 by tiagoagueda · 2 comments
Owner

The plugin keeps interviews and one calendar in step: every interview from 90 days ago onwards goes into the named calendar as a VEVENT, and new times, place, notes or a cancellation made there come back (src/postulo_dav/sync.py:193-217, :554-673). Any other event is left alone as "not from Postulo", and nothing can be paired by hand. The request:

An CalDAV event can be "paired" and data synced, using its URI, to an job interview, or other vent on Postulo.

What is wrong today

  • An alarm's text replaces the preparation notes. text_to_events (src/postulo_dav/text.py:234-265) does not track nested components, so a VALARM's DESCRIPTION overwrites the event's own. Pushed events carry the interview's reminder as a VALARM, so a pull replaces an interview's notes with the reminder's text. Confirmed by running it; the tests use empty notes (tests/test_dav.py:592-617).
  • The application's link is missing. The README promises it, but event_text passes no url to event_lines (sync.py:169-179). With no request, POSTULO_PUBLIC_URL (the wiki's Configuration) joined with the application's get_absolute_url() gives one; unset, the link is left out, not written as a bare path.

What the plugin should do

Which calendars are read or written is #13; the pairing key and re-finding a moved event are #7.

  • Pair an event with an interview. An event in a chosen calendar, within the sync's window (read with a calendar-query time range, RFC 4791 §7.8), can be paired with one of the person's interviews and kept in step. Postulo's own event for it, if any, is deleted (with If-Match) so the meeting is not shown twice.
  • Make an interview from an event. Paired with an application instead, it becomes an interview through schedule_interview, with its timeline entry and reminder; the person picks the kind.
  • Keep the event's UID, and never destroy the person's event. CalDAV forbids a write that changes a resource's UID (RFC 4791 §5.3.2.1, no-uid-conflict). An event made elsewhere is patched, not rebuilt: only the properties Postulo owns change. Deleting the interview unpairs it; only an event Postulo made is deleted. Unpaired events are left alone.
  • Read only what the event says. Each property stays with its component; DURATION counts as well as DTEND (RFC 5545 §3.6.1); the "With:" line and link Postulo wrote are told apart from the notes.
  • Carry the application's link in every event Postulo makes.

Decisions

  • "Using its URI." Reading: the event's address picks it when pairing, and #7 keeps the calendar plus UID, the address being arbitrary (RFC 4791 §5.3.2). Alternative: a Postulo link in the event's URL is the key. Recommend the first.
  • "Other event on Postulo." Reading: the rest of what the core's Calendar page draws: reminders, application deadlines, listing closing dates and offer answer-by dates (src/postulo/applications/agenda.py:197 in the core). The last three are whole days with derived UIDs, and nothing on the surface changes them. Recommend: reminders go as tasks (#12); whole days are pushed one way as all-day events, behind a switch off by default, since no feed a phone can subscribe to carries them (the web one needs a session; the API's holds interviews only). Alternatives: pair whole days both ways, which needs write services the core lacks; or a timeline entry such as a call, but entries are append-only.
  • Recurring events. Recommend leaving them out, as today (postulo/postulo#16): an interview is one meeting. Alternative: pair one occurrence (RECURRENCE-ID).
  • What a paired event made elsewhere exchanges. Recommend: times, place and cancellation, both ways; never its SUMMARY, DESCRIPTION, URL, ATTENDEE or alarms. An event with an ORGANIZER can be a scheduling object, where a write can make the server message the other participants, or be refused (RFC 6638 §3; not tried against a server), so pair it read-only. Alternative: everything, as for Postulo's own events.

Needs from the core

The parser fix and the link need none and can ship first.

New strings go through uv run postulo-messages extract, fr-fr and pt-pt filled on the commit (the test gates them), the 23 EU catalogues before a tag (uv run pytest -m release). New surface names mean repinning the core (pyproject.toml's dev group pins commit 1d6cdd7e0) and extending tests/test_surface.py.

Done when

  • An interview with notes and a reminder, moved on the phone, keeps its notes (tested).
  • A paired event made elsewhere keeps its UID and every property Postulo does not own, moves its interview when moved, and outlives the interview; one with an ORGANIZER is never written to.
  • An event paired with an application becomes an interview with its timeline entry and reminder.
  • With the switch on, whole days appear as all-day events and follow changes made here.
  • Events Postulo makes carry the application's link when POSTULO_PUBLIC_URL is set.

From the list of DAV plugin improvements of 2026-09-30.

The plugin keeps interviews and one calendar in step: every interview from 90 days ago onwards goes into the named calendar as a `VEVENT`, and new times, place, notes or a cancellation made there come back (`src/postulo_dav/sync.py:193-217`, `:554-673`). Any other event is left alone as "not from Postulo", and nothing can be paired by hand. The request: > An CalDAV event can be "paired" and data synced, using its URI, to an job interview, or other vent on Postulo. ## What is wrong today - **An alarm's text replaces the preparation notes.** `text_to_events` (`src/postulo_dav/text.py:234-265`) does not track nested components, so a `VALARM`'s `DESCRIPTION` overwrites the event's own. Pushed events carry the interview's reminder as a `VALARM`, so a pull replaces an interview's notes with the reminder's text. Confirmed by running it; the tests use empty notes (`tests/test_dav.py:592-617`). - **The application's link is missing.** The README promises it, but `event_text` passes no `url` to `event_lines` (`sync.py:169-179`). With no request, `POSTULO_PUBLIC_URL` (the wiki's *Configuration*) joined with the application's `get_absolute_url()` gives one; unset, the link is left out, not written as a bare path. ## What the plugin should do Which calendars are read or written is #13; the pairing key and re-finding a moved event are #7. - **Pair an event with an interview.** An event in a chosen calendar, within the sync's window (read with a `calendar-query` time range, RFC 4791 §7.8), can be paired with one of the person's interviews and kept in step. Postulo's own event for it, if any, is deleted (with `If-Match`) so the meeting is not shown twice. - **Make an interview from an event.** Paired with an application instead, it becomes an interview through `schedule_interview`, with its timeline entry and reminder; the person picks the kind. - **Keep the event's UID, and never destroy the person's event.** CalDAV forbids a write that changes a resource's UID (RFC 4791 §5.3.2.1, `no-uid-conflict`). An event made elsewhere is patched, not rebuilt: only the properties Postulo owns change. Deleting the interview unpairs it; only an event Postulo made is deleted. Unpaired events are left alone. - **Read only what the event says.** Each property stays with its component; `DURATION` counts as well as `DTEND` (RFC 5545 §3.6.1); the "With:" line and link Postulo wrote are told apart from the notes. - **Carry the application's link** in every event Postulo makes. ## Decisions - **"Using its URI."** Reading: the event's address picks it when pairing, and #7 keeps the calendar plus `UID`, the address being arbitrary (RFC 4791 §5.3.2). Alternative: a Postulo link in the event's `URL` is the key. Recommend the first. - **"Other event on Postulo."** Reading: the rest of what the core's Calendar page draws: reminders, application deadlines, listing closing dates and offer answer-by dates (`src/postulo/applications/agenda.py:197` in the core). The last three are whole days with derived UIDs, and nothing on the surface changes them. Recommend: reminders go as tasks (#12); whole days are pushed one way as all-day events, behind a switch off by default, since no feed a phone can subscribe to carries them (the web one needs a session; the API's holds interviews only). Alternatives: pair whole days both ways, which needs write services the core lacks; or a timeline entry such as a call, but entries are append-only. - **Recurring events.** Recommend leaving them out, as today (postulo/postulo#16): an interview is one meeting. Alternative: pair one occurrence (`RECURRENCE-ID`). - **What a paired event made elsewhere exchanges.** Recommend: times, place and cancellation, both ways; never its `SUMMARY`, `DESCRIPTION`, `URL`, `ATTENDEE` or alarms. An event with an `ORGANIZER` can be a scheduling object, where a write can make the server message the other participants, or be refused (RFC 6638 §3; not tried against a server), so pair it read-only. Alternative: everything, as for Postulo's own events. ## Needs from the core - postulo/postulo#330: `schedule_interview`, and reading the whole days. - postulo/postulo#327: where a person pairs, unpairs or makes an interview from an event; a plugin cannot draw a page (postulo/postulo#228). - postulo/postulo#326: the calendar on the link, a role (an application's deadline event beside its task), and unbinding. The parser fix and the link need none and can ship first. New strings go through `uv run postulo-messages extract`, fr-fr and pt-pt filled on the commit (the test gates them), the 23 EU catalogues before a tag (`uv run pytest -m release`). New surface names mean repinning the core (`pyproject.toml`'s dev group pins commit `1d6cdd7e0`) and extending `tests/test_surface.py`. ## Done when - An interview with notes and a reminder, moved on the phone, keeps its notes (tested). - A paired event made elsewhere keeps its UID and every property Postulo does not own, moves its interview when moved, and outlives the interview; one with an `ORGANIZER` is never written to. - An event paired with an application becomes an interview with its timeline entry and reminder. - With the switch on, whole days appear as all-day events and follow changes made here. - Events Postulo makes carry the application's link when `POSTULO_PUBLIC_URL` is set. From the list of DAV plugin improvements of 2026-09-30.
Author
Owner

From postulo/postulo-dav#14, which closed with 32cca53: one thing it asked for can only be done here.

A LANGUAGE parameter found on a event made elsewhere survives a push. The parameter is a BCP 47 language tag (RFC 5545 §3.2.10), and this issue is where a event is patched instead of rebuilt, so it is where one that is already there must be kept as it was written. If Postulo ever writes one of its own, it writes the tag in its canonical form, as the core does since postulo/postulo#337 (pt-BR, not pt-br).

Worth a test of its own here: a event carrying LANGUAGE=pt-BR on a property comes back from a push with it.

From postulo/postulo-dav#14, which closed with `32cca53`: one thing it asked for can only be done here. **A `LANGUAGE` parameter found on a event made elsewhere survives a push.** The parameter is a BCP 47 language tag (RFC 5545 §3.2.10), and this issue is where a event is patched instead of rebuilt, so it is where one that is already there must be kept as it was written. If Postulo ever writes one of its own, it writes the tag in its canonical form, as the core does since postulo/postulo#337 (`pt-BR`, not `pt-br`). Worth a test of its own here: a event carrying `LANGUAGE=pt-BR` on a property comes back from a push with it.
Author
Owner

The maintainer's list of 2026-10-02 asks for iCalendar as the format for events. Core issue postulo/postulo#661 exports every dated thing the calendar page draws, imports .ics files, and offers on the plugin surface a reader that returns plain values, keeps an alarm's text apart from the notes and never guesses a time zone as UTC.

Those are this issue's “What is wrong today” and postulo-dav#24, so text_to_events (src/postulo_dav/text.py:234) could be dropped. It also proposes a stable UID for whole days, which the whole-day decision here depends on.

This issue keeps its own scope: pairing by calendar and UID, patching events it did not make, and making an interview from a chosen event.

From the list of improvements of 2026-10-02.

The maintainer's list of 2026-10-02 asks for iCalendar as the format for events. Core issue postulo/postulo#661 exports every dated thing the calendar page draws, imports `.ics` files, and offers on the plugin surface a reader that returns plain values, keeps an alarm's text apart from the notes and never guesses a time zone as UTC. Those are this issue's “What is wrong today” and postulo-dav#24, so `text_to_events` (`src/postulo_dav/text.py:234`) could be dropped. It also proposes a stable UID for whole days, which the whole-day decision here depends on. This issue keeps its own scope: pairing by calendar and UID, patching events it did not make, and making an interview from a chosen event. From the list of improvements of 2026-10-02.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-dav#11
No description provided.