Skip to content

Commit

Permalink
feat: jsonrpc: add create_draft, draft_set_text, `draft_set_subje…
Browse files Browse the repository at this point in the history
…ct`, `draft_set_quoted_message`, `draft_set_quoted_text`
  • Loading branch information
Simon-Laux committed Jan 12, 2025
1 parent 187274d commit 3b6fb20
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 1 deletion.
129 changes: 128 additions & 1 deletion deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use types::chat::FullChat;
use types::contact::{ContactObject, VcardContact};
use types::events::Event;
use types::http::HttpResponse;
use types::message::{MessageData, MessageObject, MessageReadReceipt};
use types::message::{MessageData, MessageObject, MessageReadReceipt, QuotedText};
use types::provider_info::ProviderInfo;
use types::reactions::JSONRPCReactions;
use types::webxdc::WebxdcMessageInfo;
Expand Down Expand Up @@ -2022,6 +2022,133 @@ impl CommandApi {
}
}

/// Create a new draft (overwriting existing draft)
///
/// You can modify some fields of an existing draft while keeping it's message id (important to keep webxdc status updates) with the following methods:
/// - [Self::draft_set_text]
/// - [Self::draft_set_quoted_message]
/// - [Self::draft_set_quoted_text]
/// For other actions like changing the view type or file attachment you have to recreate the draft.
///
/// You can send the draft with [Self::send_draft]
async fn create_draft(&self, account_id: u32, chat_id: u32, data: MessageData) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
let mut message = data
.create_message(&ctx)
.await
.context("Failed to create message")?;

ChatId::new(chat_id)
.set_draft(&ctx, Some(&mut message))
.await
.context("Failed to set draft message")?;
Ok(message.get_id().to_u32())
}

/// set text of draft
async fn draft_set_text(&self, account_id: u32, msg_id: u32, text: String) -> Result<()> {
let ctx = self.get_context(account_id).await?;
let mut message = message::Message::load_from_db(&ctx, MsgId::new(msg_id)).await?;

if message.get_state() != deltachat::message::MessageState::OutDraft {
bail!("provided message is not a draft");
}

message.set_text(text);
message
.get_chat_id()
.set_draft(&ctx, Some(&mut message))
.await?;

Ok(())
}

/// set (email) subject of draft
async fn draft_set_subject(&self, account_id: u32, msg_id: u32, subject: String) -> Result<()> {
let ctx = self.get_context(account_id).await?;
let mut message = message::Message::load_from_db(&ctx, MsgId::new(msg_id)).await?;

if message.get_state() != deltachat::message::MessageState::OutDraft {
bail!("provided message is not a draft");
}

message.set_subject(subject);
message
.get_chat_id()
.set_draft(&ctx, Some(&mut message))
.await?;

Ok(())
}

/// set quoted message id of draft
async fn draft_set_quoted_message(
&self,
account_id: u32,
msg_id: u32,
quoted_message_id: Option<u32>,
) -> Result<()> {
let ctx = self.get_context(account_id).await?;
let mut message = message::Message::load_from_db(&ctx, MsgId::new(msg_id)).await?;

if message.get_state() != deltachat::message::MessageState::OutDraft {
bail!("provided message is not a draft");
}

let message_to_qoute = match quoted_message_id {
Some(msg_id) => Some(message::Message::load_from_db(&ctx, MsgId::new(msg_id)).await?),
None => None,
};

message.set_quote(&ctx, message_to_qoute.as_ref()).await?;
message
.get_chat_id()
.set_draft(&ctx, Some(&mut message))
.await?;

Ok(())
}

/// set quoted text of draft
async fn draft_set_quoted_text(
&self,
account_id: u32,
msg_id: u32,
quoted_text: Option<QuotedText>,
) -> Result<()> {
let ctx = self.get_context(account_id).await?;
let mut message = message::Message::load_from_db(&ctx, MsgId::new(msg_id)).await?;

if message.get_state() != deltachat::message::MessageState::OutDraft {
bail!("provided message is not a draft");
}

message.set_quote_text(quoted_text.map(|qt| (qt.text, qt.protect)));

message
.get_chat_id()
.set_draft(&ctx, Some(&mut message))
.await?;

Ok(())
}

/// send draft
async fn send_draft(&self, account_id: u32, msg_id: u32) -> Result<u32> {
// uses message id instead of chat id to force ui to have the right message id / know about the draft - reduce the chance of undefined behaviour
let ctx = self.get_context(account_id).await?;
let mut draft = message::Message::load_from_db(&ctx, MsgId::new(msg_id)).await?;

if draft.get_state() != deltachat::message::MessageState::OutDraft {
bail!("provided message is not a draft");
}

let chat = draft.get_chat_id();
let msg_id = chat::send_msg(&ctx, chat, &mut draft).await?.to_u32();
Ok(msg_id)
}


async fn send_videochat_invitation(&self, account_id: u32, chat_id: u32) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
chat::send_videochat_invitation(&ctx, ChatId::new(chat_id))
Expand Down
11 changes: 11 additions & 0 deletions deltachat-jsonrpc/src/api/types/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,14 @@ impl From<deltachat::ephemeral::Timer> for EphemeralTimer {
}
}
}


#[derive(Deserialize, Serialize, TypeDef, schemars::JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct QuotedText {
/// Text shown in the Quote
pub text: String,
/// protect specifies whether text should only be sent encrypted.
/// If it should, but the message is unencrypted, text is replaced with "...".
pub protect: bool
}

0 comments on commit 3b6fb20

Please sign in to comment.