EWS fixes - part 3
This commit is contained in:
@@ -9,7 +9,7 @@ use serde_json::Value;
|
||||
|
||||
use crate::db::exchange_ews_ids;
|
||||
use crate::error::Error;
|
||||
use crate::exchange_ews::calendar_map::to_jscalendar;
|
||||
use crate::exchange_ews::calendar_map::to_jscalendar_with_exceptions;
|
||||
use crate::exchange_ews::parse::{CalendarItemRaw, parse_calendar_item};
|
||||
use crate::exchange_ews::types::{CalendarItemType, ItemId};
|
||||
use crate::exchange_ews::xml::ItemShape;
|
||||
@@ -19,7 +19,8 @@ use crate::sync::TypeCounts;
|
||||
use super::attachments::{fetch_attachments, intern_attachment};
|
||||
use super::folders::FolderPlan;
|
||||
use super::items::{
|
||||
EnumerationMode, ItemRunCtx, delete_vanished, enumerate_folder, for_each_fetched_item, plan_for,
|
||||
EnumerationMode, ItemRunCtx, delete_vanished, enumerate_folder, for_each_fetched_item,
|
||||
get_items, plan_for,
|
||||
};
|
||||
|
||||
pub fn reconcile_all(
|
||||
@@ -176,7 +177,8 @@ fn apply_event(
|
||||
existing_local_id: Option<i64>,
|
||||
counts: &mut TypeCounts,
|
||||
) -> Result<(), Error> {
|
||||
let mut built = to_jscalendar(raw);
|
||||
let modified_full = fetch_modified_occurrences(ctx, raw);
|
||||
let mut built = to_jscalendar_with_exceptions(raw, &modified_full);
|
||||
attach_calendar_links(conn, ctx, raw, &mut built.data)?;
|
||||
let calendar_ids = serde_json::json!([local_folder_id]).to_string();
|
||||
let data = built.data.to_string();
|
||||
@@ -229,6 +231,33 @@ fn apply_event(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch_modified_occurrences(ctx: &ItemRunCtx<'_>, raw: &CalendarItemRaw) -> Vec<CalendarItemRaw> {
|
||||
let ids: Vec<ItemId> = raw
|
||||
.modified_occurrences
|
||||
.iter()
|
||||
.filter(|o| !o.item_id.id.is_empty())
|
||||
.map(|o| o.item_id.clone())
|
||||
.collect();
|
||||
if ids.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
match get_items(ctx, ItemShape::CalendarItem, &ids) {
|
||||
Ok(outcome) => outcome
|
||||
.messages
|
||||
.iter()
|
||||
.filter(|m| m.success)
|
||||
.filter_map(|m| parse_calendar_item(&m.inner_xml).ok())
|
||||
.filter(|occ| !occ.id.id.is_empty())
|
||||
.collect(),
|
||||
Err(e) => {
|
||||
ctx.logger.warn(&format!(
|
||||
"GetItem (calendar exceptions) failed: {e}; overrides keep time-only changes"
|
||||
));
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn attach_calendar_links(
|
||||
conn: &mut Connection,
|
||||
ctx: &ItemRunCtx<'_>,
|
||||
|
||||
@@ -269,3 +269,39 @@ fn keyword_array(item: &MessageItem) -> String {
|
||||
let value: Value = Value::Array(kws.into_iter().map(Value::String).collect());
|
||||
value.to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::keyword_array;
|
||||
use crate::exchange_ews::parse::MessageItem;
|
||||
|
||||
#[test]
|
||||
fn read_draft_flagged_and_categories_map_to_jmap_keywords() {
|
||||
let item = MessageItem {
|
||||
is_read: Some(true),
|
||||
is_draft: Some(true),
|
||||
flag_status: Some("Flagged".to_owned()),
|
||||
categories: vec!["Red Category".to_owned(), "VIP".to_owned()],
|
||||
..MessageItem::default()
|
||||
};
|
||||
let kws = keyword_array(&item);
|
||||
for expected in ["$seen", "$draft", "$flagged", "red category", "vip"] {
|
||||
assert!(kws.contains(expected), "missing {expected} in {kws}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unread_unflagged_message_has_no_seen_or_flagged() {
|
||||
let item = MessageItem {
|
||||
is_read: Some(false),
|
||||
flag_status: Some("NotFlagged".to_owned()),
|
||||
..MessageItem::default()
|
||||
};
|
||||
let kws = keyword_array(&item);
|
||||
assert!(!kws.contains("$seen"), "unread must not be $seen: {kws}");
|
||||
assert!(
|
||||
!kws.contains("$flagged"),
|
||||
"only FlagStatus=Flagged maps to $flagged: {kws}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user