diff --git a/src/rule_processor.rs b/src/rule_processor.rs new file mode 100644 index 0000000..00131ae --- /dev/null +++ b/src/rule_processor.rs @@ -0,0 +1,199 @@ +use google_gmail1::api::{BatchDeleteMessagesRequest, BatchModifyMessagesRequest}; + +use crate::{EolAction, Error, GmailClient, Result, config::EolRule, message_list::MessageList}; + +/// Rules processor to apply the configured rules to the mailbox. +pub trait RuleProcessor { + /// Find the rule and the message for a specific label + fn find_rule_and_messages_for_label( + &mut self, + label: &str, + ) -> impl std::future::Future> + Send; + /// Set the execute flag in the client + fn set_execute(&mut self, value: bool); + // /// Delete messages + // fn delete_messages( + // &mut self, + // label: &str, + // ) -> impl std::future::Future> + Send; + // /// Trash Messages + // fn trash_messages( + // &mut self, + // label: &str, + // ) -> impl std::future::Future> + Send; + /// Set rule to process + fn set_rule(&mut self, action: EolRule); + /// Report the action from the rule + fn action(&self) -> Option; + /// Prepare a list of messages to trash or delete + fn prepare(&mut self, pages: u32) -> impl std::future::Future> + Send; + /// Batch delete of messages + fn batch_delete(&self) -> impl std::future::Future> + Send; + /// Batch trash + fn batch_trash(&self) -> impl std::future::Future> + Send; +} + +impl RuleProcessor for GmailClient { + /// Add Action to the Client for processing + fn set_rule(&mut self, value: EolRule) { + self.rule = Some(value); + } + + /// Set the execute flag + fn set_execute(&mut self, value: bool) { + self.execute = value; + } + + /// The action set in the rule + fn action(&self) -> Option { + if let Some(rule) = &self.rule { + return rule.action(); + } + None + } + + /// Find the rule and messages for the label + async fn find_rule_and_messages_for_label(&mut self, label: &str) -> Result<()> { + self.add_labels(&[label.to_string()]).await?; + + if self.label_ids().is_empty() { + return Err(Error::LabelNotFoundInMailbox(label.to_string())); + } + + let Some(rule) = &self.rule else { + return Err(Error::RuleNotFound(0)); + }; + + let Some(query) = rule.eol_query() else { + return Err(Error::NoQueryStringCalculated(rule.id())); + }; + self.set_query(&query); + + log::info!("{:?}", self.messages()); + log::info!("Ready to run"); + self.prepare(0).await?; + if self.execute { + log::info!("***executing final delete messages***"); + self.batch_trash().await + } else { + log::warn!("Execution stopped for dry run"); + Ok(()) + } + } + + // /// Trash the messages + // async fn trash_messages(&mut self, label: &str) -> Result<()> { + // self.add_labels(&[label.to_string()]).await?; + + // if self.label_ids().is_empty() { + // return Err(Error::LabelNotFoundInMailbox(label.to_string())); + // } + + // let Some(rule) = &self.rule else { + // return Err(Error::RuleNotFound(0)); + // }; + + // let Some(query) = rule.eol_query() else { + // return Err(Error::NoQueryStringCalculated(rule.id())); + // }; + // self.set_query(&query); + + // log::info!("{:?}", self.messages()); + // log::info!("Ready to run"); + // self.prepare(0).await?; + // if self.execute { + // log::info!("***executing final delete messages***"); + // self.batch_trash().await + // } else { + // log::warn!("Execution stopped for dry run"); + // Ok(()) + // } + // } + + // /// Delete the messages + // async fn delete_messages(&mut self, label: &str) -> Result<()> { + // self.add_labels(&[label.to_string()]).await?; + + // if self.label_ids().is_empty() { + // return Err(Error::LabelNotFoundInMailbox(label.to_string())); + // } + + // let Some(rule) = &self.rule else { + // return Err(Error::RuleNotFound(0)); + // }; + + // let Some(query) = rule.eol_query() else { + // return Err(Error::NoQueryStringCalculated(rule.id())); + // }; + // self.set_query(&query); + + // log::info!("{:?}", self.messages()); + // log::info!("Ready to run"); + // self.prepare(0).await?; + // if self.execute { + // log::info!("***executing final delete messages***"); + // self.batch_delete().await + // } else { + // log::warn!("Execution stopped for dry run"); + + // Ok(()) + // } + // } + /// Prepare the message list for delete to be completed on execute by batch_delete + async fn prepare(&mut self, pages: u32) -> Result<()> { + self.run(pages).await + } + + /// Run the batch delete on the selected messages + async fn batch_delete(&self) -> Result<()> { + let ids = Some(self.message_ids()); + + let batch_request = BatchDeleteMessagesRequest { ids }; + + log::trace!("{batch_request:#?}"); + + let _res = self + .hub() + .users() + .messages_batch_delete(batch_request, "me") + .add_scope("https://mail.google.com/") + .doit() + .await + .map_err(Box::new)?; + + for m in self.messages() { + log::info!("Message with subject `{}` deleted.", m.subject()); + } + + Ok(()) + } + /// Move the messages to trash + async fn batch_trash(&self) -> Result<()> { + let add_label_ids = Some(Vec::from(["TRASH".to_string()])); + let ids = Some(self.message_ids()); + let remove_label_ids = Some(self.label_ids()); + + let batch_request = BatchModifyMessagesRequest { + add_label_ids, + ids, + remove_label_ids, + }; + + log::trace!("{batch_request:#?}"); + + let _res = self + .hub() + .users() + .messages_batch_modify(batch_request, "me") + .add_scope("https://www.googleapis.com/auth/gmail.modify") + .doit() + .await + .map_err(Box::new)?; + + for m in self.messages() { + log::info!("Message with subject `{}` moved to trash.", m.subject()); + } + + Ok(()) + } +}