Add Graph API compatibility for delete-mailbox and update-mailbox operations

This commit is contained in:
rustmailer
2025-11-06 23:12:44 +08:00
parent c50bd26cd9
commit 566beabb7a
5 changed files with 96 additions and 11 deletions
+5 -1
View File
@@ -181,11 +181,15 @@ impl GmailClient {
let mut body = json!({
"id": label_id,
"name": request.new_name,
"messageListVisibility": "show",
"labelListVisibility": "labelShow",
"type": "user"
});
if let Some(new_name) = &request.new_name {
body["name"] = json!(new_name);
}
if let Some(color) = &request.label_color {
body["color"] = json!({
"textColor": color.text_color,
+27
View File
@@ -417,4 +417,31 @@ impl OutlookClient {
client.post(&url, &access_token, Some(&body), false).await?;
Ok(())
}
pub async fn delete_folder(
account_id: u64,
use_proxy: Option<u64>,
folder_id: &str,
) -> RustMailerResult<()> {
let url = format!("https://graph.microsoft.com/v1.0/me/mailFolders/{folder_id}");
let client = HttpClient::new(use_proxy).await?;
let access_token = Self::get_access_token(account_id).await?;
client.delete(url.as_str(), &access_token).await
}
pub async fn rename_folder(
account_id: u64,
use_proxy: Option<u64>,
folder_id: &str,
new_name: &str,
) -> RustMailerResult<()> {
let url = format!("https://graph.microsoft.com/v1.0/me/mailFolders/{folder_id}");
let client = HttpClient::new(use_proxy).await?;
let access_token = Self::get_access_token(account_id).await?;
let data = json!({
"displayName": new_name
});
client.patch(url.as_str(), &access_token, &data).await?;
Ok(())
}
}
+1 -5
View File
@@ -219,11 +219,7 @@ impl HttpClient {
}
}
pub async fn get_bytes(
&self,
url: &str,
access_token: &str,
) -> RustMailerResult<Bytes> {
pub async fn get_bytes(&self, url: &str, access_token: &str) -> RustMailerResult<Bytes> {
let mut attempt = 0;
let max_attempts = 4;
let mut delay_ms = 500;
+18 -2
View File
@@ -6,7 +6,7 @@ use crate::{
encode_mailbox_name,
modules::{
account::{entity::MailerType, migration::AccountModel},
cache::vendor::gmail::sync::client::GmailClient,
cache::vendor::{gmail::sync::client::GmailClient, outlook::sync::client::OutlookClient},
context::executors::RUST_MAIL_CONTEXT,
error::{code::ErrorCode, RustMailerResult},
},
@@ -35,6 +35,22 @@ pub async fn delete_mailbox(account_id: u64, mailbox_name: &str) -> RustMailerRe
})?;
GmailClient::delete_label(account_id, account.use_proxy, label_id).await
}
MailerType::GraphApi => todo!(),
MailerType::GraphApi => {
let mailboxes = OutlookClient::list_mailfolders(account_id, account.use_proxy).await?;
let target_folder = mailboxes
.iter()
.find(|f| f.display_name == mailbox_name)
.cloned();
if let Some(folder) = target_folder {
OutlookClient::delete_folder(account_id, account.use_proxy, &folder.id).await?;
return Ok(());
} else {
return Err(raise_error!(
format!("Mailbox '{}' not found.", mailbox_name),
ErrorCode::ResourceNotFound
));
}
}
}
}
+45 -3
View File
@@ -6,7 +6,7 @@ use crate::{
encode_mailbox_name,
modules::{
account::{entity::MailerType, migration::AccountModel},
cache::vendor::gmail::sync::client::GmailClient,
cache::vendor::{gmail::sync::client::GmailClient, outlook::sync::client::OutlookClient},
context::executors::RUST_MAIL_CONTEXT,
error::{code::ErrorCode, RustMailerResult},
mailbox::create::LabelColor,
@@ -22,7 +22,13 @@ pub struct MailboxUpdateRequest {
/// Current name of the mailbox or label.
///
/// - For IMAP accounts, this is the existing mailbox name.
/// - For Gmail API accounts, this is the existing label name.
/// - For Gmail API accounts, this is the existing label name.
/// - For Graph API accounts, this should be the full mailbox path as displayed by
/// `list-mailboxes?remote=true`, where subfolders are separated by `/`.
/// For example, if the folder path is `test1/test2`, you must provide the full name
/// `test1/test2` instead of just `test2`.
///
/// The path format is handled internally by RustMailer to ensure consistent folder resolution.
#[oai(validator(min_length = "1", max_length = "1024"))]
pub current_name: String,
/// New name for the mailbox or label (optional).
@@ -58,6 +64,14 @@ pub async fn update_mailbox(
.await
}
MailerType::GmailApi => {
if payload.new_name.is_none() && payload.label_color.is_none() {
return Err(raise_error!(
"You must provide either `new_name` or `label_color` to update a mailbox."
.into(),
ErrorCode::InvalidParameter
));
}
let map = GmailClient::reverse_label_map(account_id, account.use_proxy, true).await?;
let label_id = map.get(&payload.current_name).ok_or_else(|| {
raise_error!(
@@ -70,6 +84,34 @@ pub async fn update_mailbox(
})?;
GmailClient::update_label(account_id, account.use_proxy, label_id, &payload).await
}
MailerType::GraphApi => todo!(),
MailerType::GraphApi => {
if payload.new_name.is_none() {
return Err(raise_error!(
"The `new_name` field is required when updating a mailbox.".into(),
ErrorCode::InvalidParameter
));
}
let mailboxes = OutlookClient::list_mailfolders(account_id, account.use_proxy).await?;
let target_folder = mailboxes
.iter()
.find(|f| f.display_name == payload.current_name)
.cloned();
if let Some(folder) = target_folder {
OutlookClient::rename_folder(
account_id,
account.use_proxy,
&folder.id,
&payload.new_name.unwrap(),
)
.await?;
return Ok(());
} else {
return Err(raise_error!(
format!("Mailbox '{}' not found.", payload.current_name),
ErrorCode::ResourceNotFound
));
}
}
}
}