Interviews booked through the API: the reminder names the hour in the server's zone #564
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#564
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?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, by following where the interview services get their time zone and language from, and booking an interview through the API with the test client.Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atnotifications/management/commands/send_due_reminders.py:85(the summary sent as the title); the rest is where it was. The scheduled sync's side of this has since been filed as #335, so this issue keeps the API and the calendar feeds and shares the helper with it.The interview services write the time of an interview into stored text: the reminder's summary, which is later sent word for word as the notification title, and the timeline entries "… scheduled for …" and "… moved from … to …". They format it in whatever zone and language are active when they run. Only a signed-in browser session activates the owner's zone and language. An API call and the scheduler's calendar sync do not, so the reminder can name the wrong hour for the interview.
applications/services.py:354-375:_when()and_interview_reminder_summary()formattimezone.localtime(...)withDATETIME_FORMAT/TIME_FORMATunder the active language.applications/services.py:414-435(schedule_interview) and:446-472(reschedule_interview) store those strings inApplicationEvent.summaryandReminder.summary.:172-187(change_status) stores "Old → New" the same way.core/middleware.py:124-146and:174-182:UserPreferencesMiddlewarefinds a profile only whenrequest.user.is_authenticated. A bearer token never logs anyone in (api/auth.py:58-66), so an API call gets the instance default zone and the languageLocaleMiddlewaretook fromAccept-Language.plugins/syncing.py:70-96:sync_connectionruns the plugin with nothing activated. postulo-dav'ssync.py:195callsreschedule_interview, so the reminder is re-worded insettings.TIME_ZONEandLANGUAGE_CODE. That path is #335.notifications/management/commands/send_due_reminders.py:85sendsreminder.summaryas the title.notify()(notifications/service.py:49-55) switches the language, but it cannot change words that are already stored, and it does not switch the zone.America/New_Yorkand French, and the instance is inEurope/Paris. An agent books a video interview throughPOST /api/v1/interviewsfor 15:00 UTC, which is 10:00 in New York. The reminder is stored as "Interview tomorrow: Video call at Aperture Science, 16:00", in English and in Paris time. The day before, the phone announces 16:00 for a 10:00 interview. The timeline reads "Video call scheduled for 2 Nov 2026, 16:00". Moving the event in the person's own calendar does the same through the CalDAV sync (#335). The/interviews/calendar.icsfeed also words eachSUMMARY(applications/ical.py:147) in the calendar client'sAccept-Language.core.context.acting_for(user), that enterstimezone.override(profile.time_zone or site.default_time_zone())andtranslation.override(notifications.service.language_for(user)).TokenAuth/ScopedAuth.authenticate, or in a small wrapper around each operation) and in the ICS feeds. #335 asks for the same helper aroundplugins.syncing.sync_connectionforconnection.owner; whichever lands first adds it, and the other uses it.notify's override, with the zone overridden too.Related to #335 (open), which covers the same fault when a scheduled sync moves an interview, to #224 (closed), which made the reminder re-worded on reschedule, and to #223 (closed), which moved notification language to the recipient but did not cover text stored before delivery or the time zone.
Done when
tests/test_interviews.py: an interview booked throughPOST /api/v1/interviewsfor a profile inAmerica/New_Yorkhas a reminder, and a timeline entry, that name 10:00 for a 15:00 UTC start while the instance zone isEurope/Paris./interviews/calendar.icsfor that profile asserts eachSUMMARYis worded in the profile's language whateverAccept-Languagethe calendar client sends. (The sync pass has its test in #335.)