From cc57a6aec89f7a2aa3a73faa04c878258f7d7cdc Mon Sep 17 00:00:00 2001 From: Jeremiah Russell Date: Thu, 30 Oct 2025 09:35:06 +0000 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(gmail):=20consoli?= =?UTF-8?q?date=20batch=20processing=20logic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - introduce process_in_chunks for DRY principle - remove redundant chunking logic from batch_delete - update documentation for API scope requirements --- src/rule_processor.rs | 67 ++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/src/rule_processor.rs b/src/rule_processor.rs index 7e6efa9..c9bbc9d 100644 --- a/src/rule_processor.rs +++ b/src/rule_processor.rs @@ -470,9 +470,8 @@ impl RuleProcessor for GmailClient { /// /// # API Scope Requirements /// - /// Uses `https://www.googleapis.com/auth/gmail.modify` scope for secure, - /// minimal privilege access. This scope provides sufficient permissions - /// for message deletion while following security best practices. + /// Uses `https://mail.google.com/` scope as it is required to immediately and + /// permanently delete threads and messages, bypassing Trash. async fn batch_delete(&mut self) -> Result<()> { let message_ids = MessageList::message_ids(self); @@ -485,45 +484,8 @@ impl RuleProcessor for GmailClient { self.log_messages("Message with subject `", "` permanently deleted") .await?; - let (chunks, remainder) = message_ids.as_chunks::<1000>(); - log::trace!( - "Message list chopped into {} chunks with {} ids in the remainder", - chunks.len(), - remainder.len() - ); - - if !chunks.is_empty() { - for (i, chunk) in chunks.iter().enumerate() { - log::trace!("Processing chunk {i}"); - self.call_batch_delete(chunk).await?; - } - } - - if !remainder.is_empty() { - log::trace!("Processing remainder."); - self.call_batch_delete(remainder).await?; - } - - Ok(()) - } - - async fn call_batch_delete(&self, ids: &[String]) -> Result<()> { - let ids = Some(Vec::from(ids)); - let batch_request = BatchDeleteMessagesRequest { ids }; - log::trace!("{batch_request:#?}"); - - let res = self - .hub() - .users() - .messages_batch_delete(batch_request, "me") - .add_scope(GMAIL_DELETE_SCOPE) - .doit() - .await - .map_err(Box::new); - - log::trace!("Batch delete response {res:?}"); - - res?; + self.process_in_chunks(message_ids, EolAction::Delete) + .await?; Ok(()) } @@ -587,6 +549,27 @@ impl RuleProcessor for GmailClient { Ok(()) } + async fn call_batch_delete(&self, ids: &[String]) -> Result<()> { + let ids = Some(Vec::from(ids)); + let batch_request = BatchDeleteMessagesRequest { ids }; + log::trace!("{batch_request:#?}"); + + let res = self + .hub() + .users() + .messages_batch_delete(batch_request, "me") + .add_scope(GMAIL_DELETE_SCOPE) + .doit() + .await + .map_err(Box::new); + + log::trace!("Batch delete response {res:?}"); + + res?; + + Ok(()) + } + async fn call_batch_trash(&self, ids: &[String]) -> Result<()> { let ids = Some(Vec::from(ids)); let add_label_ids = Some(vec![TRASH_LABEL.to_string()]);