botserver/src/calendar/caldav.rs
Rodrigo Rodriguez (Pragmatismo) a886478548 Implement database persistence for dashboards, legal, and compliance modules
- Add PostgreSQL persistence for dashboards module (was returning empty vec![])
  - Tables: dashboards, dashboard_widgets, dashboard_data_sources, dashboard_filters,
    dashboard_widget_data_sources, conversational_queries
  - Full CRUD operations with spawn_blocking pattern

- Add PostgreSQL persistence for legal module (was using in-memory HashMap)
  - Tables: legal_documents, legal_document_versions, cookie_consents, consent_history,
    legal_acceptances, data_deletion_requests, data_export_requests
  - GDPR-compliant consent tracking and document management

- Add PostgreSQL persistence for compliance module (was returning empty results)
  - Tables: compliance_checks, compliance_issues, compliance_audit_log, compliance_evidence,
    compliance_risk_assessments, compliance_risks, compliance_training_records,
    compliance_access_reviews
  - Support for GDPR, SOC2, ISO27001, HIPAA, PCI-DSS frameworks

- Add migration files for all new tables
- Update schema.rs with new table definitions and joinables
- Register new routes in main.rs
- Add recursion_limit = 512 for macro expansion
2026-01-13 00:07:22 -03:00

173 lines
5.2 KiB
Rust

use axum::{
http::StatusCode,
response::{IntoResponse, Response},
routing::get,
Router,
};
use std::sync::Arc;
use crate::basic::keywords::book::CalendarEngine;
use crate::shared::state::AppState;
pub fn create_caldav_router(_engine: Arc<CalendarEngine>) -> Router<Arc<AppState>> {
Router::new()
.route("/caldav", get(caldav_root))
.route("/caldav/principals", get(caldav_principals))
.route("/caldav/calendars", get(caldav_calendars))
.route("/caldav/calendars/:calendar_id", get(caldav_calendar))
.route(
"/caldav/calendars/:calendar_id/:event_id.ics",
get(caldav_event).put(caldav_put_event),
)
}
async fn caldav_root() -> impl IntoResponse {
Response::builder()
.status(StatusCode::OK)
.header("DAV", "1, 2, calendar-access")
.header("Content-Type", "application/xml; charset=utf-8")
.body(
r#"<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>/caldav/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype>
<D:collection/>
</D:resourcetype>
<D:displayname>GeneralBots CalDAV Server</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>"#
.to_string(),
)
.unwrap_or_default()
}
async fn caldav_principals() -> impl IntoResponse {
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/xml; charset=utf-8")
.body(
r#"<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>/caldav/principals/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype>
<D:collection/>
<D:principal/>
</D:resourcetype>
<C:calendar-home-set>
<D:href>/caldav/calendars/</D:href>
</C:calendar-home-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>"#
.to_string(),
)
.unwrap_or_default()
}
async fn caldav_calendars() -> impl IntoResponse {
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/xml; charset=utf-8")
.body(
r#"<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>/caldav/calendars/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype>
<D:collection/>
</D:resourcetype>
<D:displayname>Calendars</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/caldav/calendars/default/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype>
<D:collection/>
<C:calendar/>
</D:resourcetype>
<D:displayname>Default Calendar</D:displayname>
<C:supported-calendar-component-set>
<C:comp name="VEVENT"/>
<C:comp name="VTODO"/>
</C:supported-calendar-component-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>"#
.to_string(),
)
.unwrap_or_default()
}
async fn caldav_calendar() -> impl IntoResponse {
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/xml; charset=utf-8")
.body(
r#"<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>/caldav/calendars/default/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype>
<D:collection/>
<C:calendar/>
</D:resourcetype>
<D:displayname>Default Calendar</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>"#
.to_string(),
)
.unwrap_or_default()
}
async fn caldav_event() -> impl IntoResponse {
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "text/calendar; charset=utf-8")
.body(
r"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-
BEGIN:VEVENT
UID:placeholder@generalbots.com
DTSTAMP:20240101T000000Z
DTSTART:20240101T090000Z
DTEND:20240101T100000Z
SUMMARY:Placeholder Event
END:VEVENT
END:VCALENDAR"
.to_string(),
)
.unwrap_or_default()
}
async fn caldav_put_event() -> impl IntoResponse {
Response::builder()
.status(StatusCode::CREATED)
.header("ETag", "\"placeholder-etag\"")
.body(String::new())
.unwrap_or_default()
}