cull_gmail/rule_processor.rs
1use google_gmail1::api::{BatchDeleteMessagesRequest, BatchModifyMessagesRequest};
2
3use crate::{EolAction, Error, GmailClient, Result, config::EolRule, message_list::MessageList};
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 // /// Delete messages
15 // fn delete_messages(
16 // &mut self,
17 // label: &str,
18 // ) -> impl std::future::Future<Output = Result<()>> + Send;
19 // /// Trash Messages
20 // fn trash_messages(
21 // &mut self,
22 // label: &str,
23 // ) -> impl std::future::Future<Output = Result<()>> + Send;
24 /// Set rule to process
25 fn set_rule(&mut self, action: EolRule);
26 /// Report the action from the rule
27 fn action(&self) -> Option<EolAction>;
28 /// Prepare a list of messages to trash or delete
29 fn prepare(&mut self, pages: u32) -> impl std::future::Future<Output = Result<()>> + Send;
30 /// Batch delete of messages
31 fn batch_delete(&self) -> impl std::future::Future<Output = Result<()>> + Send;
32 /// Batch trash
33 fn batch_trash(&self) -> impl std::future::Future<Output = Result<()>> + Send;
34}
35
36impl RuleProcessor for GmailClient {
37 /// Add Action to the Client for processing
38 fn set_rule(&mut self, value: EolRule) {
39 self.rule = Some(value);
40 }
41
42 /// Set the execute flag
43 fn set_execute(&mut self, value: bool) {
44 self.execute = value;
45 }
46
47 /// The action set in the rule
48 fn action(&self) -> Option<EolAction> {
49 if let Some(rule) = &self.rule {
50 return rule.action();
51 }
52 None
53 }
54
55 /// Find the rule and messages for the label
56 async fn find_rule_and_messages_for_label(&mut self, label: &str) -> Result<()> {
57 self.add_labels(&[label.to_string()])?;
58
59 if self.label_ids().is_empty() {
60 return Err(Error::LabelNotFoundInMailbox(label.to_string()));
61 }
62
63 let Some(rule) = &self.rule else {
64 return Err(Error::RuleNotFound(0));
65 };
66
67 let Some(query) = rule.eol_query() else {
68 return Err(Error::NoQueryStringCalculated(rule.id()));
69 };
70 self.set_query(&query);
71
72 log::info!("{:?}", self.messages());
73 log::info!("Ready to run");
74 self.prepare(0).await?;
75 if self.execute {
76 log::info!("***executing final delete messages***");
77 self.batch_trash().await
78 } else {
79 log::warn!("Execution stopped for dry run");
80 Ok(())
81 }
82 }
83
84 // /// Trash the messages
85 // async fn trash_messages(&mut self, label: &str) -> Result<()> {
86 // self.add_labels(&[label.to_string()]).await?;
87
88 // if self.label_ids().is_empty() {
89 // return Err(Error::LabelNotFoundInMailbox(label.to_string()));
90 // }
91
92 // let Some(rule) = &self.rule else {
93 // return Err(Error::RuleNotFound(0));
94 // };
95
96 // let Some(query) = rule.eol_query() else {
97 // return Err(Error::NoQueryStringCalculated(rule.id()));
98 // };
99 // self.set_query(&query);
100
101 // log::info!("{:?}", self.messages());
102 // log::info!("Ready to run");
103 // self.prepare(0).await?;
104 // if self.execute {
105 // log::info!("***executing final delete messages***");
106 // self.batch_trash().await
107 // } else {
108 // log::warn!("Execution stopped for dry run");
109 // Ok(())
110 // }
111 // }
112
113 // /// Delete the messages
114 // async fn delete_messages(&mut self, label: &str) -> Result<()> {
115 // self.add_labels(&[label.to_string()]).await?;
116
117 // if self.label_ids().is_empty() {
118 // return Err(Error::LabelNotFoundInMailbox(label.to_string()));
119 // }
120
121 // let Some(rule) = &self.rule else {
122 // return Err(Error::RuleNotFound(0));
123 // };
124
125 // let Some(query) = rule.eol_query() else {
126 // return Err(Error::NoQueryStringCalculated(rule.id()));
127 // };
128 // self.set_query(&query);
129
130 // log::info!("{:?}", self.messages());
131 // log::info!("Ready to run");
132 // self.prepare(0).await?;
133 // if self.execute {
134 // log::info!("***executing final delete messages***");
135 // self.batch_delete().await
136 // } else {
137 // log::warn!("Execution stopped for dry run");
138
139 // Ok(())
140 // }
141 // }
142 /// Prepare the message list for delete to be completed on execute by batch_delete
143 async fn prepare(&mut self, pages: u32) -> Result<()> {
144 self.get_messages(pages).await
145 }
146
147 /// Run the batch delete on the selected messages
148 async fn batch_delete(&self) -> Result<()> {
149 let ids = Some(self.message_ids());
150
151 let batch_request = BatchDeleteMessagesRequest { ids };
152
153 log::trace!("{batch_request:#?}");
154
155 let _res = self
156 .hub()
157 .users()
158 .messages_batch_delete(batch_request, "me")
159 .add_scope("https://mail.google.com/")
160 .doit()
161 .await
162 .map_err(Box::new)?;
163
164 for m in self.messages() {
165 log::info!("Message with subject `{}` deleted.", m.subject());
166 }
167
168 Ok(())
169 }
170 /// Move the messages to trash
171 async fn batch_trash(&self) -> Result<()> {
172 let add_label_ids = Some(Vec::from(["TRASH".to_string()]));
173 let ids = Some(self.message_ids());
174 let remove_label_ids = Some(self.label_ids());
175
176 let batch_request = BatchModifyMessagesRequest {
177 add_label_ids,
178 ids,
179 remove_label_ids,
180 };
181
182 log::trace!("{batch_request:#?}");
183
184 let _res = self
185 .hub()
186 .users()
187 .messages_batch_modify(batch_request, "me")
188 .add_scope("https://www.googleapis.com/auth/gmail.modify")
189 .doit()
190 .await
191 .map_err(Box::new)?;
192
193 for m in self.messages() {
194 log::info!("Message with subject `{}` moved to trash.", m.subject());
195 }
196
197 Ok(())
198 }
199}