use ews_proc_macros::operation_response;
use serde::Deserialize;
use xml_struct::XmlSerialize;
use crate::{BaseFolderId, Groups, ItemShape, Items, View, MESSAGES_NS_URI};
#[derive(Clone, Debug, XmlSerialize)]
#[xml_struct(default_ns = MESSAGES_NS_URI)]
#[operation_response(FindItemResponseMessage)]
pub struct FindItem {
#[xml_struct(attribute)]
pub traversal: Traversal,
pub item_shape: ItemShape,
#[xml_struct(flatten)]
pub view: Option<View>,
pub parent_folder_ids: Vec<BaseFolderId>,
}
#[derive(Clone, Debug, XmlSerialize)]
#[xml_struct(text)]
pub enum Traversal {
Shallow,
SoftDeleted,
Associated,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub struct FindItemResponseMessage {
pub root_folder: RootFolder,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub struct RootFolder {
#[serde(rename = "@IndexedPagingOffset")]
pub indexed_paging_offset: Option<usize>,
#[serde(rename = "@NumeratorOffset")]
pub numerator_offset: Option<usize>,
#[serde(rename = "@AbsoluteDenominator")]
pub absolute_denominator: Option<usize>,
#[serde(rename = "@TotalItemsInView")]
pub total_items_in_view: Option<usize>,
#[serde(rename = "@IncludesLastItemInRange")]
pub includes_last_item_in_range: Option<bool>,
pub items: Items,
pub groups: Option<Groups>,
}
#[cfg(test)]
mod tests {
use crate::{
test_utils::{assert_deserialized_content, assert_serialized_content, minify_xml},
BasePoint, BaseShape, Groups, ItemId, Items, Message, RealItem, ResponseClass,
ResponseMessages,
};
use super::*;
#[test]
fn test_serialize_find_item_indexed_page_item_view() {
let find_item = FindItem {
traversal: Traversal::Shallow,
item_shape: ItemShape {
base_shape: BaseShape::IdOnly,
..Default::default()
},
parent_folder_ids: vec![BaseFolderId::DistinguishedFolderId {
id: "deleteditems".to_string(),
change_key: None,
}],
view: Some(View::IndexedPageItemView {
max_entries_returned: Some(6),
offset: 0,
base_point: BasePoint::Beginning,
}),
};
let expected = minify_xml(
r#"
<FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" Traversal="Shallow">
<ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
</ItemShape>
<IndexedPageItemView MaxEntriesReturned="6" BasePoint="Beginning" Offset="0"/>
<ParentFolderIds>
<t:DistinguishedFolderId Id="deleteditems"/>
</ParentFolderIds>
</FindItem>"#,
);
assert_serialized_content(&find_item, "FindItem", &expected);
}
#[test]
fn test_serialize_find_item_fractional_page_item_view() {
let find_item = FindItem {
traversal: Traversal::Shallow,
item_shape: ItemShape {
base_shape: BaseShape::IdOnly,
..Default::default()
},
parent_folder_ids: vec![BaseFolderId::DistinguishedFolderId {
id: "inbox".to_string(),
change_key: None,
}],
view: Some(View::FractionalPageItemView {
max_entries_returned: Some(12),
numerator: 2,
denominator: 3,
}),
};
let expected = minify_xml(
r#"
<FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" Traversal="Shallow">
<ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
</ItemShape>
<FractionalPageItemView MaxEntriesReturned="12" Numerator="2" Denominator="3"/>
<ParentFolderIds>
<t:DistinguishedFolderId Id="inbox"/>
</ParentFolderIds>
</FindItem>"#,
);
assert_serialized_content(&find_item, "FindItem", &expected);
}
#[test]
fn test_serialize_find_item_calendar_view() {
let find_item = FindItem {
traversal: Traversal::Shallow,
item_shape: ItemShape {
base_shape: BaseShape::IdOnly,
..Default::default()
},
parent_folder_ids: vec![BaseFolderId::DistinguishedFolderId {
id: "calendar".to_string(),
change_key: None,
}],
view: Some(View::CalendarView {
max_entries_returned: Some(2),
start_date: "2006-05-18T00:00:00-08:00".to_string(),
end_date: "2006-05-19T00:00:00-08:00".to_string(),
}),
};
let expected = minify_xml(
r#"
<FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" Traversal="Shallow">
<ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
</ItemShape>
<CalendarView MaxEntriesReturned="2" StartDate="2006-05-18T00:00:00-08:00" EndDate="2006-05-19T00:00:00-08:00"/>
<ParentFolderIds>
<t:DistinguishedFolderId Id="calendar"/>
</ParentFolderIds>
</FindItem>"#,
);
assert_serialized_content(&find_item, "FindItem", &expected);
}
#[test]
fn test_serialize_find_item_contacts_view() {
let find_item = FindItem {
traversal: Traversal::Shallow,
item_shape: ItemShape {
base_shape: BaseShape::IdOnly,
..Default::default()
},
parent_folder_ids: vec![BaseFolderId::DistinguishedFolderId {
id: "contacts".to_string(),
change_key: None,
}],
view: Some(View::ContactsView {
max_entries_returned: Some(3),
initial_name: Some("Kelly Rollin".to_string()),
final_name: None,
}),
};
let expected = minify_xml(
r#"
<FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" Traversal="Shallow">
<ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
</ItemShape>
<ContactsView MaxEntriesReturned="3" InitialName="Kelly Rollin"/>
<ParentFolderIds>
<t:DistinguishedFolderId Id="contacts"/>
</ParentFolderIds>
</FindItem>"#,
);
assert_serialized_content(&find_item, "FindItem", &expected);
}
#[test]
fn test_deserialize_root_folder() {
let xml = r#"
<m:RootFolder
IndexedPagingOffset="1"
NumeratorOffset="1"
AbsoluteDenominator="1"
IncludesLastItemInRange="true" TotalItemsInView="10">
<Items/>
</m:RootFolder>"#;
let expected = RootFolder {
indexed_paging_offset: Some(1),
numerator_offset: Some(1),
absolute_denominator: Some(1),
total_items_in_view: Some(10),
includes_last_item_in_range: Some(true),
items: Items { inner: vec![] },
groups: None,
};
assert_deserialized_content(xml, expected);
}
#[test]
fn test_deserialize_find_item_response_message() {
let content = r#"
<FindItemResponse
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder IncludesLastItemInRange="true" TotalItemsInView="10">
<Items>
<t:Message>
<t:ItemId Id="AS4AUn=" ChangeKey="fsVU4==" />
</t:Message>
</Items>
<Groups/>
</m:RootFolder>
</m:FindItemResponseMessage>
</m:ResponseMessages>
</FindItemResponse>"#;
let response = FindItemResponse {
response_messages: ResponseMessages {
response_messages: vec![ResponseClass::Success(FindItemResponseMessage {
root_folder: RootFolder {
indexed_paging_offset: None,
numerator_offset: None,
absolute_denominator: None,
total_items_in_view: Some(10),
includes_last_item_in_range: Some(true),
items: Items {
inner: vec![RealItem::Message(Message {
item_id: Some(ItemId {
id: "AS4AUn=".to_string(),
change_key: Some("fsVU4==".to_string()),
}),
..Default::default()
})],
},
groups: Some(Groups { inner: vec![] }),
},
})],
},
};
assert_deserialized_content(content, response);
}
}