mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 15:51:15 +00:00
feat(calendar): read-only ICS feeds for tenant and staff
GET /v1/public/calendar/{token} serves an RFC 5545 calendar under a
token-as-secret URL (private Google/Outlook link model). Staff feeds
contain only that member's bookings; the tenant feed tags each event
with the staff member. Window is -30d to +180d; cancelled bookings map
to STATUS:CANCELLED, waitlisted/pending to TENTATIVE + TRANSPARENT.
Summaries resolve service or class-session titles, descriptions carry
localized contact labels, locations resolve to names.
Feed tokens live on tenants/staff (migration 00015) and are managed via
GET /v1/calendar/feed plus POST /v1/calendar/feed/rotate — rotating a
scope invalidates the old URL. ICS rendering is hand-rolled: TEXT
escaping, CRLF, 75-octet folding on rune boundaries.
Settings gains a "Kalendář (ICS)" card with copyable URLs and two-step
rotation per scope; demo mode points at the real seeded tokens.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
796c06ae66
commit
6c3b2bf6bf
14 files changed
+1354
-3
No files matched your search
@@ -16,6 +16,7 @@ tags:
|
||||
- name: Tenant
|
||||
- name: Catalog
|
||||
- name: Billing
|
||||
- name: Calendar
|
||||
- name: SMS
|
||||
- name: Jobs
|
||||
paths:
|
||||
@@ -1258,6 +1259,85 @@ paths:
|
||||
$ref: "#/components/schemas/SessionRoster"
|
||||
"404":
|
||||
description: Class session not found
|
||||
# ---------------- Calendar ----------------
|
||||
/v1/calendar/feed:
|
||||
get:
|
||||
tags: [Calendar]
|
||||
operationId: getCalendarFeedInfo
|
||||
security:
|
||||
- bearerAuth: []
|
||||
summary: Feed tokens for the tenant and every staff member
|
||||
description: >-
|
||||
Returns the read-only ICS feed token for the whole tenant plus one per
|
||||
staff member. Tokens are secrets — anyone holding a feed URL can read
|
||||
that calendar, same model as private Google/Outlook calendar links.
|
||||
responses:
|
||||
"200":
|
||||
description: Current feed tokens
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CalendarFeedInfo"
|
||||
"404":
|
||||
description: Tenant membership not found
|
||||
/v1/calendar/feed/rotate:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
operationId: rotateCalendarFeedToken
|
||||
security:
|
||||
- bearerAuth: []
|
||||
summary: Invalidate a feed URL and issue a fresh token
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [scope]
|
||||
properties:
|
||||
scope:
|
||||
type: string
|
||||
enum: [tenant, staff]
|
||||
staffId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Required when scope is staff; must belong to the tenant
|
||||
responses:
|
||||
"200":
|
||||
description: Newly issued token and feed path
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CalendarFeedEntry"
|
||||
"400":
|
||||
description: Invalid scope or foreign staff member
|
||||
"404":
|
||||
description: Tenant membership not found
|
||||
/v1/public/calendar/{token}:
|
||||
get:
|
||||
tags: [Calendar]
|
||||
operationId: getCalendarFeed
|
||||
summary: Read-only ICS calendar feed
|
||||
description: >-
|
||||
Token-as-secret calendar subscription endpoint. `{token}` may carry a
|
||||
`.ics` suffix, which is ignored. The feed covers bookings from 30 days
|
||||
back to 180 days ahead; cancelled bookings appear with
|
||||
STATUS:CANCELLED and waitlisted entries as TENTATIVE/TRANSPARENT.
|
||||
parameters:
|
||||
- in: path
|
||||
name: token
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: iCalendar document
|
||||
content:
|
||||
text/calendar:
|
||||
schema:
|
||||
type: string
|
||||
"404":
|
||||
description: Unknown or rotated feed token
|
||||
# ---------------- Billing ----------------
|
||||
/v1/billing/subscription:
|
||||
get:
|
||||
@@ -1822,6 +1902,36 @@ components:
|
||||
waitlistPosition:
|
||||
type: integer
|
||||
description: 1-based queue spot for waitlisted class bookings; absent otherwise
|
||||
CalendarFeedEntry:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: Feed secret — embed in the subscription URL
|
||||
feedPath:
|
||||
type: string
|
||||
description: API-relative path ending in .ics; prefix with the API base URL
|
||||
StaffCalendarFeedEntry:
|
||||
type: object
|
||||
properties:
|
||||
staffId:
|
||||
type: string
|
||||
format: uuid
|
||||
displayName:
|
||||
type: string
|
||||
token:
|
||||
type: string
|
||||
feedPath:
|
||||
type: string
|
||||
CalendarFeedInfo:
|
||||
type: object
|
||||
properties:
|
||||
tenant:
|
||||
$ref: "#/components/schemas/CalendarFeedEntry"
|
||||
staff:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/StaffCalendarFeedEntry"
|
||||
DashboardBookingRequest:
|
||||
type: object
|
||||
required: [customerName, customerEmail, startsAt]
|
||||
|
||||
Reference in new issue
Block a user