A modernization pass on operator-facing surfaces: source connection details are now editable instead of delete-and-readd; SMTP gains env-var configuration and proper port-465 support; the From: mailbox stops mangling addresses without display names; and team event-type management permissions are tightened so management routes can't be reached via the read-only availability surface.
Added
- Edit CalDAV sources (closes #72, PR #73) —
GET /dashboard/sources/{id}/edit(form pre-filled, password field reads "Leave blank to keep existing") andPOST /dashboard/sources/{id}/edit(apply), both scoped byuser_id. CLI mirror:calrs source update <id-prefix> [--name ...] [--url ...] [--username ...] [--password].--passwordis a flag that prompts viarpasswordfor scripted rotation. Empty password on either surface preserves the stored encrypted blob untouched. URL changes passvalidate_caldav_urlfor SSRF parity between web and CLI - SMTP via environment variables with TLS mode support (PR #56) —
CALRS_SMTP_HOST,CALRS_SMTP_USERNAME,CALRS_SMTP_PASSWORD,CALRS_SMTP_FROM_EMAILrequired;CALRS_SMTP_PORT(default 587),CALRS_SMTP_TLS_MODE(starttls/tls),CALRS_SMTP_FROM_NAMEoptional. Env vars take priority over the DB; partial config errors loudly. NewSmtpTlsModeenum branchessend_emailonrelay()(implicit TLS) vsstarttls_relay()to fix the port-465 hang. Applies to DB-configured SMTP too via newtls_modecolumn (migration 052, defaults to'starttls');calrs config smtpprompt asks for the mode. Admin panel surfaces env-sourced status.SmtpConfig'sDebugimpl now redacts the password so it can't leak through tracing or test output
Fixed
- From: mailbox handles missing display name and special characters (PR #104) —
calrs config smtp-testproducedError: Invalid inputwheneverfrom_namewasNone: the old fallback yielded a string likeyou@example.com <you@example.com>whose two@'s failed RFC 5322 parsing. All 17 send sites now build From through a newSmtpConfig::mailbox_from()helper usingMailbox::new(Option<String>, Address), which also handles display names containing commas and other characters that need quoting. Unit test locks in both theNonecase and theSome("Name, With Comma")case - Team event type management gated through a single capability check (PR #55) — personal
/dashboard/event-types/{slug}/*mutation routes now requireet.team_id IS NULL; team-event mutation requires team admin; slug-collision resolution made deterministic via subquery +ORDER BY (team_id IS NULL) DESC. Behaviour change worth noting:delete_invitenow strictly requirescan_manage_event_type, so a non-admin team member who created an internal-event invite via the "any authenticated user" path can no longer delete that invite (let it expire or hit max-uses; owners, team admins, and global admins are unaffected). NewOptionalAuthUserextractor with sharedresolve_session_userlets public surfaces selectively widen access for logged-in viewers. Team members and global admins can now bypass the team-level invite token on public events of private teams;team_profile_pagelists private/internal event-type titles + slugs for logged-in team members (booking stays invite-gated). 8 new regression tests cover the full manageability matrix
Internal
- 671 tests total (up from 650 in 1.11.0), all green on pre-commit
- Migration 052 (
smtp_config.tls_mode)