CalDAV Scheduling - part 6

This commit is contained in:
mdecimus
2025-06-21 19:53:23 +02:00
parent 068457ea87
commit 367ddeeae4
24 changed files with 869 additions and 73 deletions

View File

@@ -201,6 +201,10 @@ impl CalendarDeleteRequestHandler for Server {
self.commit_batch(batch).await.caused_by(trc::location!())?;
if send_itip {
self.notify_task_queue();
}
Ok(HttpResponse::new(StatusCode::NO_CONTENT))
}
}

View File

@@ -17,6 +17,7 @@ use calcard::{
Entry, Parser,
icalendar::{
ICalendarComponentType, ICalendarEntry, ICalendarMethod, ICalendarProperty, ICalendarValue,
Uri,
},
};
use common::{Server, auth::AccessToken};
@@ -289,10 +290,18 @@ impl CalendarSchedulingHandler for Server {
(ICalendarProperty::Uid, Some(ICalendarValue::Text(_))) => {
uid = Some(entry);
}
(ICalendarProperty::Organizer, Some(ICalendarValue::Text(_))) => {
(
ICalendarProperty::Organizer,
Some(ICalendarValue::Text(_) | ICalendarValue::Uri(Uri::Location(_))),
) => {
organizer = Some(entry);
}
(ICalendarProperty::Attendee, Some(ICalendarValue::Text(value))) => {
(
ICalendarProperty::Attendee,
Some(
ICalendarValue::Text(value) | ICalendarValue::Uri(Uri::Location(value)),
),
) => {
if let Some(email) =
sanitize_email(value.strip_prefix("mailto:").unwrap_or(value.as_str()))
{

View File

@@ -162,6 +162,11 @@ impl CalendarUpdateRequestHandler for Server {
Err(e) => return Err(e),
}
if ical == event.inner.data.event {
// No changes, return existing event
return Ok(HttpResponse::new(StatusCode::NO_CONTENT));
}
// Validate quota
let extra_bytes =
(bytes.len() as u64).saturating_sub(u32::from(event.inner.size) as u64);
@@ -214,8 +219,7 @@ impl CalendarUpdateRequestHandler for Server {
&& access_token.has_permission(Permission::CalendarSchedulingSend)
&& new_event.data.event_range_end() > now
{
let result = if let Some(schedule_tag) = &mut new_event.schedule_tag {
*schedule_tag += 1;
let result = if new_event.schedule_tag.is_some() {
itip_update(
&mut new_event.data.event,
&old_ical,
@@ -227,9 +231,25 @@ impl CalendarUpdateRequestHandler for Server {
match result {
Ok(messages) => {
if messages.iter().map(|r| r.to.len()).sum::<usize>()
let mut is_organizer = false;
if messages
.iter()
.map(|r| {
is_organizer = r.from_organizer;
r.to.len()
})
.sum::<usize>()
< self.core.groupware.itip_outbound_max_recipients
{
// Only update schedule tag if the user is the organizer
if is_organizer {
if let Some(schedule_tag) = &mut new_event.schedule_tag {
*schedule_tag += 1;
} else {
new_event.schedule_tag = Some(1);
}
}
itip_messages = Some(ItipMessages::new(messages));
} else {
return Err(DavError::Condition(DavErrorCondition::new(
@@ -248,6 +268,11 @@ impl CalendarUpdateRequestHandler for Server {
.with_details(err.to_string()),
));
}
// Event changed, but there are no iTIP messages to send
if let Some(schedule_tag) = &mut new_event.schedule_tag {
*schedule_tag += 1;
}
}
}
}

View File

@@ -1378,6 +1378,15 @@ impl PropFindRequestHandler for Server {
DavValue::CData(ical),
));
}
(
CalDavProperty::CalendarData(_),
ArchivedResource::CalendarScheduling(event),
) => {
fields.push(DavPropertyValue::new(
property.clone(),
DavValue::CData(event.inner.itip.to_string()),
));
}
(CalDavProperty::ScheduleTag, ArchivedResource::CalendarEvent(event))
if event.inner.schedule_tag.is_some() =>
{
@@ -1406,7 +1415,7 @@ impl PropFindRequestHandler for Server {
fields.push(DavPropertyValue::new(
property.clone(),
vec![Href(format!(
"{}/{}/{default_cal}",
"{}/{}/{default_cal}/",
DavResourceName::Cal.base_path(),
item.name.split('/').nth(3).unwrap_or_default()
))],