🏗️(caldav) migrate from davical to sabre/dav
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The Calendar application is a modern, self-hosted calendar solution that combines a Django REST API backend with a separate CalDAV server (DAViCal) for standards-compliant calendar data storage and synchronization. This architecture provides both a modern web interface and full CalDAV protocol support for compatibility with standard calendar clients.
|
||||
The Calendar application is a modern, self-hosted calendar solution that combines a Django REST API backend with a separate CalDAV server for standards-compliant calendar data storage and synchronization. This architecture provides both a modern web interface and full CalDAV protocol support for compatibility with standard calendar clients.
|
||||
|
||||
## System Architecture
|
||||
|
||||
@@ -34,7 +34,7 @@ The Calendar application is a modern, self-hosted calendar solution that combine
|
||||
│ HTTP/CalDAV Protocol
|
||||
│
|
||||
┌────────▼─────────────────────────────────────┐
|
||||
│ DAViCal Server │
|
||||
│ CalDAV Server │
|
||||
│ (CalDAV Protocol Implementation) │
|
||||
│ - Calendar storage │
|
||||
│ - Event storage (iCalendar format) │
|
||||
@@ -46,7 +46,7 @@ The Calendar application is a modern, self-hosted calendar solution that combine
|
||||
┌────────▼─────────────────────────────────────┐
|
||||
│ PostgreSQL Database │
|
||||
│ - Django models (users, calendars metadata) │
|
||||
│ - DAViCal schema (calendar data) │
|
||||
│ - CalDAV server schema (calendar data) │
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -60,7 +60,7 @@ The Django backend serves as the **orchestration layer** and **business logic en
|
||||
- **User Management & Authentication**: OIDC authentication via Keycloak, user profiles, sessions, authorization
|
||||
- **Calendar Metadata Management**: Calendar creation/deletion, sharing, visibility settings, display preferences
|
||||
- **REST API Layer**: Modern RESTful API for the web frontend (JSON, standard HTTP methods, versioned at `/api/v1.0/`)
|
||||
- **CalDAV Proxy**: Proxies CalDAV requests to DAViCal, handles authentication translation, URL routing, discovery endpoint
|
||||
- **CalDAV Proxy**: Proxies CalDAV requests to CalDAV server, handles authentication translation, URL routing, discovery endpoint
|
||||
- **Business Logic**: Calendar sharing logic, permission checks, data validation, integration coordination
|
||||
|
||||
**Data Storage:**
|
||||
@@ -69,11 +69,11 @@ The Django backend serves as the **orchestration layer** and **business logic en
|
||||
- Sharing relationships
|
||||
- Application configuration
|
||||
|
||||
**Important**: Django does NOT store actual calendar events. Events are stored in DAViCal.
|
||||
**Important**: Django does NOT store actual calendar events. Events are stored in the CalDAV server.
|
||||
|
||||
### DAViCal CalDAV Server
|
||||
### CalDAV Server
|
||||
|
||||
DAViCal is a **standards-compliant CalDAV server** that handles all calendar data storage and protocol operations.
|
||||
The CalDAV server is a **standards-compliant CalDAV server** that handles all calendar data storage and protocol operations.
|
||||
|
||||
**Primary Responsibilities:**
|
||||
- **Calendar Data Storage**: Stores actual calendar events in iCalendar format, manages calendar collections
|
||||
@@ -82,9 +82,9 @@ DAViCal is a **standards-compliant CalDAV server** that handles all calendar dat
|
||||
- **Database Schema**: Uses PostgreSQL with its own schema for calendar data
|
||||
|
||||
**Authentication Integration:**
|
||||
- Trusts authentication from Django backend via `X-Forwarded-User` header
|
||||
- Users with password `*` are externally authenticated
|
||||
- Custom authentication hook validates forwarded user headers
|
||||
- Uses Apache authentication backend which reads `REMOTE_USER` environment variable
|
||||
- Django proxy sets `X-Forwarded-User` header, which the CalDAV server converts to `REMOTE_USER`
|
||||
- All communication is via HTTP - no direct database access from Django
|
||||
|
||||
### Frontend (Next.js)
|
||||
|
||||
@@ -98,17 +98,19 @@ The frontend provides the user interface and interacts with both REST API and Ca
|
||||
|
||||
### Design Decision: CalDAV Server Separation
|
||||
|
||||
The decision to use a separate CalDAV server (DAViCal) rather than implementing CalDAV directly in Django was made for several reasons:
|
||||
The decision to use a separate CalDAV server rather than implementing CalDAV directly in Django was made for several reasons:
|
||||
|
||||
1. **Standards Compliance**: DAViCal is a mature, well-tested CalDAV server that fully implements RFC 4791. Implementing CalDAV from scratch would be error-prone and time-consuming.
|
||||
1. **Standards Compliance**: Using a mature, well-tested CalDAV server that fully implements RFC 4791. Implementing CalDAV from scratch would be error-prone and time-consuming.
|
||||
|
||||
2. **Protocol Complexity**: CalDAV is built on WebDAV, involving complex XML handling, property management, and collection hierarchies. DAViCal handles all of this complexity.
|
||||
2. **Protocol Complexity**: CalDAV is built on WebDAV, involving complex XML handling, property management, and collection hierarchies. A dedicated CalDAV server handles all of this complexity.
|
||||
|
||||
3. **Maintenance**: Using a proven, maintained CalDAV server reduces maintenance burden and ensures compatibility with various CalDAV clients.
|
||||
|
||||
4. **Focus**: Django backend can focus on business logic, user management, and REST API, while DAViCal handles calendar protocol operations.
|
||||
4. **Focus**: Django backend can focus on business logic, user management, and REST API, while the CalDAV server handles calendar protocol operations.
|
||||
|
||||
5. **Shared database**: DAViCal was specifically selected because it stores its data into Postgres, which use use in all LaSuite projects.
|
||||
5. **Shared database**: The CalDAV server stores its data into Postgres, which we use in all LaSuite projects.
|
||||
|
||||
6. **Clean separation**: All communication between Django and the CalDAV server is via HTTP, ensuring clean separation of concerns and no direct database access.
|
||||
|
||||
### Benefits
|
||||
|
||||
@@ -119,7 +121,7 @@ The decision to use a separate CalDAV server (DAViCal) rather than implementing
|
||||
|
||||
2. **Separation of Concerns**
|
||||
- Django handles business logic and user management
|
||||
- DAViCal handles calendar protocol and data storage
|
||||
- CalDAV server handles calendar protocol and data storage
|
||||
- Each component focuses on its core competency
|
||||
|
||||
3. **Flexibility**
|
||||
@@ -133,7 +135,7 @@ The decision to use a separate CalDAV server (DAViCal) rather than implementing
|
||||
- Can update components independently
|
||||
|
||||
5. **Performance**
|
||||
- DAViCal is optimized for CalDAV operations
|
||||
- CalDAV server is optimized for CalDAV operations
|
||||
- Django can focus on application logic
|
||||
- Database can be optimized separately for each use case
|
||||
|
||||
@@ -144,55 +146,56 @@ The decision to use a separate CalDAV server (DAViCal) rather than implementing
|
||||
TODO: should this only be via caldav too?
|
||||
|
||||
1. **Frontend** → POST `/api/v1.0/calendars` (REST API)
|
||||
2. **Django Backend**: Validates request, creates `Calendar` model, calls DAViCal to create calendar collection
|
||||
3. **DAViCal**: Receives MKCALENDAR request, creates calendar collection, returns calendar path
|
||||
4. **Django Backend**: Stores DAViCal path in `Calendar.davical_path`, returns calendar data to frontend
|
||||
2. **Django Backend**: Validates request, creates `Calendar` model, calls CalDAV server to create calendar collection
|
||||
3. **CalDAV Server**: Receives MKCALENDAR request, creates calendar collection, returns calendar path
|
||||
4. **Django Backend**: Stores CalDAV server path in `Calendar.caldav_path`, returns calendar data to frontend
|
||||
|
||||
### Creating an Event
|
||||
|
||||
Events are created directly via CalDAV protocol:
|
||||
|
||||
1. **Frontend** → PUT `/api/v1.0/caldav/{user}/{calendar}/{event_uid}.ics` (CalDAV)
|
||||
2. **Django Backend**: `CalDAVProxyView` authenticates user, forwards request to DAViCal with authentication headers
|
||||
3. **DAViCal**: Receives PUT request with iCalendar data, stores event in calendar collection
|
||||
2. **Django Backend**: `CalDAVProxyView` authenticates user, forwards request to CalDAV server with authentication headers
|
||||
3. **CalDAV Server**: Receives PUT request with iCalendar data, stores event in calendar collection
|
||||
4. **Django Backend**: Forwards CalDAV response to frontend
|
||||
|
||||
### CalDAV Client Access
|
||||
|
||||
1. **CalDAV Client** → PROPFIND `/api/v1.0/caldav/` (CalDAV protocol)
|
||||
2. **Django Backend**: Authenticates user via Django session, forwards request to DAViCal with `X-Forwarded-User` header
|
||||
3. **DAViCal**: Processes CalDAV request, returns CalDAV response
|
||||
2. **Django Backend**: Authenticates user via Django session, forwards request to CalDAV server with `X-Forwarded-User` header
|
||||
3. **CalDAV Server**: Processes CalDAV request, returns CalDAV response
|
||||
4. **Django Backend**: Forwards response to client
|
||||
|
||||
## Integration Points
|
||||
|
||||
### User Synchronization
|
||||
|
||||
When a user is created in Django, they must also exist in DAViCal. The `ensure_user_exists()` method automatically creates DAViCal users when needed, called before any DAViCal operation.
|
||||
Users are automatically created in the CalDAV server when they first access it. The CalDAV server's Apache authentication backend reads the `REMOTE_USER` environment variable, which is set from the `X-Forwarded-User` header sent by Django. No explicit user creation is needed - the CalDAV server will create principals on-demand.
|
||||
|
||||
### Calendar Creation
|
||||
|
||||
When creating a calendar via REST API:
|
||||
1. Django creates `Calendar` model with metadata
|
||||
2. Django calls DAViCal via HTTP to create calendar collection
|
||||
3. Django stores DAViCal path in `Calendar.davical_path`
|
||||
2. Django calls CalDAV server via HTTP to create calendar collection
|
||||
3. Django stores CalDAV server path in `Calendar.caldav_path`
|
||||
|
||||
### Authentication Translation
|
||||
|
||||
Django sessions are translated to DAViCal authentication:
|
||||
Django sessions are translated to CalDAV server authentication:
|
||||
- Django adds `X-Forwarded-User` header with user email
|
||||
- DAViCal's custom authentication hook validates this header
|
||||
- Users have password `*` indicating external authentication
|
||||
- CalDAV server converts `X-Forwarded-User` to `REMOTE_USER` environment variable
|
||||
- CalDAV server's Apache authentication backend reads `REMOTE_USER` for authentication
|
||||
- All communication is via HTTP - no direct database access
|
||||
|
||||
### URL Routing
|
||||
|
||||
CalDAV clients expect specific URL patterns. The CalDAV proxy handles path translation:
|
||||
- Discovery endpoint at `.well-known/caldav` redirects to `/api/v1.0/caldav/`
|
||||
- Proxy forwards requests to DAViCal with correct paths
|
||||
- Proxy forwards requests to CalDAV server with correct paths
|
||||
|
||||
## Database Schema
|
||||
|
||||
Both Django and DAViCal use the same PostgreSQL database in a local Docker install, but maintain separate schemas:
|
||||
Both Django and the CalDAV server use the same PostgreSQL database in a local Docker install, but maintain separate schemas:
|
||||
|
||||
**Django Schema (public schema):**
|
||||
- `calendars_user` - User accounts
|
||||
@@ -200,11 +203,13 @@ Both Django and DAViCal use the same PostgreSQL database in a local Docker insta
|
||||
- `caldav_calendarshare` - Sharing relationships
|
||||
- Other Django app tables
|
||||
|
||||
**DAViCal Schema (public schema, same database):**
|
||||
- `usr` - DAViCal user records
|
||||
- `principal` - DAViCal principals
|
||||
- `collection` - Calendar collections
|
||||
- `dav_resource` - Calendar resources (events)
|
||||
- Other DAViCal-specific tables
|
||||
**CalDAV Server Schema (public schema, same database):**
|
||||
- `users` - CalDAV server user records (for digest auth, not used with Apache auth)
|
||||
- `principals` - CalDAV server principals
|
||||
- `calendars` - Calendar collections
|
||||
- `calendarinstances` - Calendar instance metadata
|
||||
- `calendarobjects` - Calendar resources (events)
|
||||
- `calendarchanges` - Change tracking
|
||||
- Other CalDAV server-specific tables
|
||||
|
||||
This allows them to share the database locally while keeping data organized.
|
||||
This allows them to share the database locally while keeping data organized. Note that Django never directly accesses CalDAV server tables - all communication is via HTTP.
|
||||
|
||||
Reference in New Issue
Block a user