cull_gmail/
rule_processor.rs

1use google_gmail1::api::{BatchDeleteMessagesRequest, BatchModifyMessagesRequest};
2
3use crate::{EolAction, Error, GmailClient, Result, message_list::MessageList, rules::EolRule};
4
5/// Rules processor to apply the configured rules to the mailbox.
6pub trait RuleProcessor {
7    /// Find the rule and the message for a specific label
8    fn find_rule_and_messages_for_label(
9        &mut self,
10        label: &str,
11    ) -> impl std::future::Future<Output = Result<()>> + Send;
12    /// Set the execute flag in the client
13    fn set_execute(&mut self, value: bool);
14    /// Set rule to process
15    fn set_rule(&mut self, action: EolRule);
16    /// Report the action from the rule
17    fn action(&self) -> Option<EolAction>;
18    /// Prepare a list of messages to trash or delete
19    fn prepare(&mut self, pages: u32) -> impl std::future::Future<Output = Result<()>> + Send;
20    /// Batch delete of messages
21    fn batch_delete(&self) -> impl std::future::Future<Output = Result<()>> + Send;
22    /// Batch trash
23    fn batch_trash(&self) -> impl std::future::Future<Output = Result<()>> + Send;
24}
25
26impl RuleProcessor for GmailClient {
27    /// Add Action to the Client for processing
28    fn set_rule(&mut self, value: EolRule) {
29        self.rule = Some(value);
30    }
31
32    /// Set the execute flag
33    fn set_execute(&mut self, value: bool) {
34        self.execute = value;
35    }
36
37    /// The action set in the rule  
38    fn action(&self) -> Option<EolAction> {
39        if let Some(rule) = &self.rule {
40            return rule.action();
41        }
42        None
43    }
44
45    /// Find the rule and messages for the label
46    async fn find_rule_and_messages_for_label(&mut self, label: &str) -> Result<()> {
47        self.add_labels(&[label.to_string()])?;
48
49        if self.label_ids().is_empty() {
50            return Err(Error::LabelNotFoundInMailbox(label.to_string()));
51        }
52
53        let Some(rule) = &self.rule else {
54            return Err(Error::RuleNotFound(0));
55        };
56
57        let Some(query) = rule.eol_query() else {
58            return Err(Error::NoQueryStringCalculated(rule.id()));
59        };
60        self.set_query(&query);
61
62        log::info!("{:?}", self.messages());
63        log::info!("Ready to run");
64        self.prepare(0).await?;
65        if self.execute {
66            log::info!("***executing final delete messages***");
67            self.batch_trash().await
68        } else {
69            log::warn!("Execution stopped for dry run");
70            Ok(())
71        }
72    }
73
74    /// Prepare the message list for delete to be completed on execute by batch_delete
75    async fn prepare(&mut self, pages: u32) -> Result<()> {
76        self.get_messages(pages).await
77    }
78
79    /// Run the batch delete on the selected messages
80    async fn batch_delete(&self) -> Result<()> {
81        let ids = Some(self.message_ids());
82
83        let batch_request = BatchDeleteMessagesRequest { ids };
84
85        log::trace!("{batch_request:#?}");
86
87        let _res = self
88            .hub()
89            .users()
90            .messages_batch_delete(batch_request, "me")
91            .add_scope("https://mail.google.com/")
92            .doit()
93            .await
94            .map_err(Box::new)?;
95
96        for m in self.messages() {
97            log::info!("Message with subject `{}` deleted.", m.subject());
98        }
99
100        Ok(())
101    }
102    /// Move the messages to trash
103    async fn batch_trash(&self) -> Result<()> {
104        let add_label_ids = Some(Vec::from(["TRASH".to_string()]));
105        let ids = Some(self.message_ids());
106        let remove_label_ids = Some(self.label_ids());
107
108        let batch_request = BatchModifyMessagesRequest {
109            add_label_ids,
110            ids,
111            remove_label_ids,
112        };
113
114        log::trace!("{batch_request:#?}");
115
116        let _res = self
117            .hub()
118            .users()
119            .messages_batch_modify(batch_request, "me")
120            .add_scope("https://www.google.com/")
121            .doit()
122            .await
123            .map_err(Box::new)?;
124
125        for m in self.messages() {
126            log::info!("Message with subject `{}` moved to trash.", m.subject());
127        }
128
129        Ok(())
130    }
131}