♻️ refactor(gmail): consolidate batch processing logic

- introduce process_in_chunks for DRY principle
- remove redundant chunking logic from batch_delete
- update documentation for API scope requirements
This commit is contained in:
Jeremiah Russell
2025-10-30 09:35:06 +00:00
committed by Jeremiah Russell
parent 99d9c09aa1
commit cc57a6aec8

View File

@@ -470,9 +470,8 @@ impl RuleProcessor for GmailClient {
/// ///
/// # API Scope Requirements /// # API Scope Requirements
/// ///
/// Uses `https://www.googleapis.com/auth/gmail.modify` scope for secure, /// Uses `https://mail.google.com/` scope as it is required to immediately and
/// minimal privilege access. This scope provides sufficient permissions /// permanently delete threads and messages, bypassing Trash.
/// for message deletion while following security best practices.
async fn batch_delete(&mut self) -> Result<()> { async fn batch_delete(&mut self) -> Result<()> {
let message_ids = MessageList::message_ids(self); let message_ids = MessageList::message_ids(self);
@@ -485,45 +484,8 @@ impl RuleProcessor for GmailClient {
self.log_messages("Message with subject `", "` permanently deleted") self.log_messages("Message with subject `", "` permanently deleted")
.await?; .await?;
let (chunks, remainder) = message_ids.as_chunks::<1000>(); self.process_in_chunks(message_ids, EolAction::Delete)
log::trace!( .await?;
"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?;
Ok(()) Ok(())
} }
@@ -587,6 +549,27 @@ impl RuleProcessor for GmailClient {
Ok(()) 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<()> { async fn call_batch_trash(&self, ids: &[String]) -> Result<()> {
let ids = Some(Vec::from(ids)); let ids = Some(Vec::from(ids));
let add_label_ids = Some(vec![TRASH_LABEL.to_string()]); let add_label_ids = Some(vec![TRASH_LABEL.to_string()]);