Skip to content

Commit

Permalink
Created UpdateItem and added necessary trait implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
tobypilling committed Oct 21, 2024
1 parent c080aad commit 416442d
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ pub mod get_folder;
pub mod get_item;
pub mod sync_folder_hierarchy;
pub mod sync_folder_items;
pub mod update_item;
128 changes: 123 additions & 5 deletions src/types/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct ItemShape {
}

/// An identifier for a property on an Exchange entity.
#[derive(Debug, XmlSerialize)]
#[derive(Debug, Deserialize, XmlSerialize)]
#[xml_struct(variant_ns_prefix = "t")]
pub enum PathToElement {
/// An identifier for an extended MAPI property.
Expand Down Expand Up @@ -162,7 +162,7 @@ pub struct ExtendedFieldURI {
/// A well-known MAPI property set identifier.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri#distinguishedpropertysetid-attribute>
#[derive(Clone, Copy, Debug, XmlSerialize)]
#[derive(Clone, Copy, Debug, Deserialize, XmlSerialize)]
#[xml_struct(text)]
pub enum DistinguishedPropertySet {
Address,
Expand All @@ -177,10 +177,32 @@ pub enum DistinguishedPropertySet {
UnifiedMessaging,
}

/// Identifies the type of conflict resolution to try during an update. The default value is AutoResolve.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem#conflictresolution-attribute>
#[derive(Clone, Copy, Debug, Deserialize, XmlSerialize)]
#[xml_struct(text)]
pub enum ConflictResolution {
NeverOverwrite,
AutoResolve,
AlwaysOverwrite,
}

/// The action an Exchange server will take upon creating or updating a `Message` item.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem#messagedisposition-attribute>
#[derive(Clone, Copy, Debug, Deserialize, XmlSerialize)]
#[xml_struct(text)]
pub enum MessageDisposition {
SaveOnly,
SendOnly,
SendAndSaveCopy,
}

/// The type of the value of a MAPI property.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri#propertytype-attribute>
#[derive(Clone, Copy, Debug, XmlSerialize)]
#[derive(Clone, Copy, Debug, Deserialize, XmlSerialize)]
#[xml_struct(text)]
pub enum PropertyType {
ApplicationTime,
Expand Down Expand Up @@ -297,7 +319,7 @@ pub struct FolderId {
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemids>
// N.B.: Commented-out variants are not yet implemented.
#[derive(Debug, XmlSerialize)]
#[derive(Debug, Deserialize, XmlSerialize)]
#[xml_struct(variant_ns_prefix = "t")]
pub enum BaseItemId {
/// An identifier for a standard Exchange item.
Expand Down Expand Up @@ -458,7 +480,7 @@ impl XmlSerialize for DateTime {
/// An email message.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/message-ex15websvcsotherref>
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, XmlSerialize)]
#[serde(rename_all = "PascalCase")]
pub struct Message {
/// The MIME content of the item.
Expand Down Expand Up @@ -528,6 +550,65 @@ pub struct Message {
pub conversation_id: Option<ItemId>,
}


// Add this Default implementation
impl Default for Message {
fn default() -> Self {
Self {
is_read: None,
mime_content: None,
item_id: ItemId {
id: "".to_string(),
change_key: None,
},
parent_folder_id: None,
item_class: None,
subject: None,
sensitivity: None,
body: None,
attachments: None,
date_time_received: None,
size: None,
categories: None,
importance: None,
in_reply_to: None,
is_submitted: None,
is_draft: None,
is_from_me: None,
is_resend: None,
is_unmodified: None,
internet_message_headers: None,
date_time_sent: None,
date_time_created: None,
reminder_due_by: None,
reminder_is_set: None,
reminder_minutes_before_start: None,
display_cc: None,
display_to: None,
has_attachments: None,
culture: None,
sender: None,
to_recipients: None,
cc_recipients: None,
bcc_recipients: None,
is_read_receipt_requested: None,
is_delivery_receipt_requested: None,
conversation_index: None,
conversation_topic: None,
from: None,
internet_message_id: None,
is_response_requested: None,
reply_to: None,
received_by: None,
received_representing: None,
last_modified_name: None,
last_modified_time: None,
is_associated: None,
conversation_id: None,
}
}
}

/// A list of attachments.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/attachments-ex15websvcsotherref>
Expand Down Expand Up @@ -917,6 +998,43 @@ pub struct MessageXml {
pub back_off_milliseconds: Option<usize>,
}

/// Represents a change to an individual item, including the item ID and updates.
#[derive(Debug, Deserialize, XmlSerialize)]
pub struct ItemChange {
#[serde(rename = "t:ItemId")]
pub item_id: BaseItemId, // Represents the <t:ItemId> element with Id and ChangeKey.

#[serde(rename = "t:Updates")]
pub updates: Updates, // Represents the <t:Updates> element containing the changes.
}

/// Represents a list of item changes without an explicit container tag.
#[derive(Debug, Deserialize, XmlSerialize)]
pub struct ItemChanges {
#[serde(rename = "t:ItemChange")]
pub item_changes: Vec<ItemChange>,
}

/// Struct representing the field update operation.
///
/// This struct contains details of the field that needs to be updated (in this case, marking a message as read/unread).
#[derive(Debug, Deserialize, XmlSerialize)]
pub struct SetItemField {
#[serde(rename = "t:FieldURI")]
pub field_uri: PathToElement, // Reference to the field being updated.
#[serde(rename = "t:Message")]
pub message: Message, // The new value for the specified field.
}

/// Struct representing updates to be applied to an item.
///
/// This struct is used to create an UpdateItem request to mark emails as read or unread.
#[derive(Debug, Deserialize, XmlSerialize)]
pub struct Updates {
#[serde(rename = "t:SetItemField")]
pub set_item_field: SetItemField,
}

#[cfg(test)]
mod tests {
use quick_xml::Writer;
Expand Down
149 changes: 149 additions & 0 deletions src/types/update_item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use crate::types::common::{BaseItemId, Updates, ItemChange, ItemChanges, ConflictResolution, MessageDisposition, PathToElement, Importance};
use crate::{
types::sealed::EnvelopeBodyContents, Items, Operation,
OperationResponse, ResponseClass, ResponseCode,
};
use serde::Deserialize;
use xml_struct::XmlSerialize;

/// Represents the UpdateItem operation for interacting with the EWS server.
#[derive(Debug, Deserialize, XmlSerialize)]
#[serde(rename_all = "PascalCase")]
pub struct UpdateItem {
/// Describes how the item will be handled after it is updated.
/// The MessageDisposition attribute is required for message items, including meeting
/// messages such as meeting cancellations, meeting requests, and meeting responses.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemshape>
pub message_disposition: MessageDisposition,

/// Identifies the type of conflict resolution to try during an update.
/// The default value is AutoResolve.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem#conflictresolution-attribute>
pub conflict_resolution: ConflictResolution,

/// Contains an array of ItemChange elements that identify items and
/// the updates to apply to the items.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemchanges>
pub item_changes: ItemChanges, // Represents the list of item changes to be included in the request.
}

impl UpdateItem {
/// Creates a new UpdateItem instance for marking a message as read/unread.
pub fn new_is_read(item_id: BaseItemId, is_read: bool) -> Self {
let item_change = ItemChange {
item_id,
updates: Updates::new_is_read(is_read),
};

UpdateItem {
message_disposition: MessageDisposition::SaveOnly,
conflict_resolution: ConflictResolution::AutoResolve,
item_changes: ItemChanges { item_changes: vec![item_change] },
}
}

/// Creates a new UpdateItem instance for changing the importance of a message.
pub fn new_importance(item_id: BaseItemId, importance: Importance) -> Self {
let item_change = ItemChange {
item_id,
updates: Updates::new_importance(importance),
};

UpdateItem {
message_disposition: MessageDisposition::SaveOnly,
conflict_resolution: ConflictResolution::AutoResolve,
item_changes: ItemChanges { item_changes: vec![item_change] },
}
}

/// Adds another `ItemChange` to the `UpdateItem` request.
pub fn add_item_change(&mut self, item_change: ItemChange) {
self.item_changes.item_changes.push(item_change);
}
}

impl Updates {
/// Creates a new `Updates` instance for marking a message as read/unread.
pub fn new_is_read(is_read: bool) -> Self {
Updates {
set_item_field: crate::types::common::SetItemField {
field_uri: PathToElement::FieldURI {
field_URI: "message:IsRead".to_string(),
},
message: crate::types::common::Message {
is_read: Some(is_read),
..Default::default()
},
},
}
}

/// Creates a new `Updates` instance for changing the importance of a message.
pub fn new_importance(importance: Importance) -> Self {
Updates {
set_item_field: crate::types::common::SetItemField {
field_uri: PathToElement::FieldURI {
field_URI: "message:Importance".to_string(),
},
message: crate::types::common::Message {
importance: Some(importance),
..Default::default()
},
},
}
}
}



impl Operation for UpdateItem {
type Response = UpdateItemResponse; // Define the appropriate response type if needed.
}

impl EnvelopeBodyContents for UpdateItem {
fn name() -> &'static str {
"UpdateItem"
}
}

/// A response to an [`UpdateItem`] request.
///
/// See <https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem>
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct UpdateItemResponse {
pub response_messages: ResponseMessages,
}


impl OperationResponse for UpdateItemResponse {}

impl EnvelopeBodyContents for UpdateItemResponse {
fn name() -> &'static str {
"UpdateItemResponse"
}
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ResponseMessages {
pub update_item_response_message: Vec<UpdateItemResponseMessage>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct UpdateItemResponseMessage {
/// The status of the corresponding request, i.e. whether it succeeded or
/// resulted in an error.
#[serde(rename = "@ResponseClass")]
pub response_class: ResponseClass,

pub response_code: Option<ResponseCode>,

pub message_text: Option<String>,

pub items: Items,
}

0 comments on commit 416442d

Please sign in to comment.