use crate::resources::event::EventResource; use crate::CalDavContext; use crate::Error; use actix_web::http::header::ContentType; use actix_web::web::{Data, Path}; use actix_web::{HttpRequest, HttpResponse}; use anyhow::Result; use quick_xml::events::BytesText; use roxmltree::{Node, NodeType}; use rustical_auth::{AuthInfoExtractor, CheckAuthentication}; use rustical_dav::namespace::Namespace; use rustical_dav::resource::HandlePropfind; use rustical_dav::xml_snippets::generate_multistatus; use rustical_store::calendar::{Calendar, CalendarStore, Event}; use std::sync::Arc; use tokio::sync::RwLock; async fn _parse_filter(filter_node: &Node<'_, '_>) { for comp_filter_node in filter_node.children() { if comp_filter_node.tag_name().name() != "comp-filter" { dbg!("wtf", comp_filter_node.tag_name().name()); continue; } for filter in filter_node.children() { match filter.tag_name().name() { // {} _ => { dbg!("unknown filter", filter.tag_name()); } } } } } async fn handle_report_calendar_query( query_node: Node<'_, '_>, request: HttpRequest, events: Vec, cal_store: Arc>, ) -> Result { let prop_node = query_node .children() .find(|n| n.node_type() == NodeType::Element && n.tag_name().name() == "prop") .ok_or(Error::BadRequest)?; let props: Vec<&str> = prop_node .children() .map(|node| node.tag_name().name()) .collect(); let mut event_results = Vec::new(); for event in events { let path = format!("{}/{}", request.path(), event.get_uid()); let event_resource = EventResource { cal_store: cal_store.clone(), path: path.clone(), event, }; event_results.push(event_resource.propfind(props.clone())?); } let output = generate_multistatus(vec![Namespace::Dav, Namespace::CalDAV], |writer| { for result in event_results { writer.write_event(quick_xml::events::Event::Text(BytesText::from_escaped( result, )))?; } Ok(()) })?; Ok(HttpResponse::MultiStatus() .content_type(ContentType::xml()) .body(output)) } pub async fn route_report_calendar( context: Data>, body: String, path: Path<(String, String)>, request: HttpRequest, _auth: AuthInfoExtractor, ) -> Result { // TODO: Check authorization let (_principal, cid) = path.into_inner(); let doc = roxmltree::Document::parse(&body).map_err(|_e| Error::BadRequest)?; let query_node = doc.root_element(); let events = context.store.read().await.get_events(&cid).await.unwrap(); dbg!(&body); // TODO: implement filtering match query_node.tag_name().name() { "calendar-query" => {} "calendar-multiget" => {} _ => return Err(Error::BadRequest), }; handle_report_calendar_query(query_node, request, events, context.store.clone()).await } pub async fn handle_mkcol_calendar_set( store: &RwLock, prop_node: Node<'_, '_>, cid: String, owner: String, ) -> Result<()> { let mut cal = Calendar { owner, id: cid.clone(), ..Default::default() }; for prop in prop_node.children() { match prop.tag_name().name() { "displayname" => { cal.name = prop.text().map(|s| s.to_string()); } "timezone" => { cal.timezone = prop.text().map(|s| s.to_string()); } "calendar-color" => { cal.color = prop.text().map(|s| s.to_string()); } "calendar-description" => { cal.description = prop.text().map(|s| s.to_string()); } "calendar-timezone" => { cal.timezone = prop.text().map(|s| s.to_string()); } _ => { println!("unsupported mkcol tag: {}", prop.tag_name().name()) } } } store.write().await.insert_calendar(cid, cal).await?; Ok(()) } pub async fn route_mkcol_calendar( path: Path<(String, String)>, body: String, auth: AuthInfoExtractor, context: Data>, ) -> Result { let (_principal, cid) = path.into_inner(); let doc = roxmltree::Document::parse(&body).map_err(|_e| Error::BadRequest)?; let mkcol_node = doc.root_element(); match mkcol_node.tag_name().name() { "mkcol" => {} _ => return Err(Error::BadRequest), } // TODO: Why does the spec (rfc5689) allow multiple elements but only one resource? :/ // Well, for now just bother with the first one let set_node = mkcol_node.first_element_child().ok_or(Error::BadRequest)?; match set_node.tag_name().name() { "set" => {} _ => return Err(Error::BadRequest), } let prop_node = set_node.first_element_child().ok_or(Error::BadRequest)?; if prop_node.tag_name().name() != "prop" { return Err(Error::BadRequest); } handle_mkcol_calendar_set( &context.store, prop_node, cid.clone(), auth.inner.user_id.clone(), ) .await?; Ok(HttpResponse::Created().body("")) }