mirror of
https://github.com/chatmail/core.git
synced 2026-04-20 15:06:30 +03:00
feat: allow the user to replace maps integration (#5678)
with this PR, when an `.xdc` with `request_integration = map` in the manifest is added to the "Saved Messages" chat, it is used _locally_ as an replacement for the shipped maps.xdc (other devices will see the `.xdc` but not use it) this allows easy development and adapting the map to use services that work better in some area. there are lots of known discussions and ideas about adding more barriers of safety. however, after internal discussions, we decided to move forward and also to allow internet, if requested by an integration (as discussed at https://github.com/deltachat/deltachat-core-rust/pull/3516). the gist is to ease development and to make users who want to adapt, actionable _now_, without making things too hard and adding too high barriers or stressing our own resources/power too much. note, that things are still experimental and will be the next time - without the corresponding switch being enabled, nothing will work at all, so we can be quite relaxed here :) for android/ios, things will work directly. for desktop, allow_internet needs to be accepted unconditionally from core. for the future, we might add a question before using an integration and/or add signing. or sth. completely different - but for now, the thing is to get started. nb: "integration" field in the webxdc-info is experimental as well and should not be used in UIs at all currently, it may vanish again and is there mainly for simplicity of the code; therefore, no need to document that. successor of https://github.com/deltachat/deltachat-core-rust/pull/5461 this is how it looks like currently - again, please note that all that is an experiment! <img width=320 src=https://github.com/deltachat/deltachat-core-rust/assets/9800740/f659c891-f46a-4e28-9d0a-b6783d69be8d> <img width=320 src=https://github.com/deltachat/deltachat-core-rust/assets/9800740/54549b3c-a894-4568-9e27-d5f1caea2d22> ... when going out of experimental, there are loots of ideas, eg. changing "Start" to "integrate"
This commit is contained in:
@@ -57,14 +57,34 @@ impl Context {
|
||||
}
|
||||
|
||||
// Check if a Webxdc shall be used as an integration and remember that.
|
||||
pub(crate) async fn update_webxdc_integration_database(&self, msg: &Message) -> Result<()> {
|
||||
if msg.viewtype == Viewtype::Webxdc && msg.param.get_int(Param::WebxdcIntegration).is_some()
|
||||
{
|
||||
self.set_config_internal(
|
||||
Config::WebxdcIntegration,
|
||||
Some(&msg.id.to_u32().to_string()),
|
||||
)
|
||||
.await?;
|
||||
pub(crate) async fn update_webxdc_integration_database(
|
||||
&self,
|
||||
msg: &mut Message,
|
||||
context: &Context,
|
||||
) -> Result<()> {
|
||||
if msg.viewtype == Viewtype::Webxdc {
|
||||
let is_integration = if msg.param.get_int(Param::WebxdcIntegration).is_some() {
|
||||
true
|
||||
} else if msg.chat_id.is_self_talk(context).await? {
|
||||
let info = msg.get_webxdc_info(context).await?;
|
||||
if info.request_integration == "map" {
|
||||
msg.param.set_int(Param::WebxdcIntegration, 1);
|
||||
msg.update_param(context).await?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if is_integration {
|
||||
self.set_config_internal(
|
||||
Config::WebxdcIntegration,
|
||||
Some(&msg.id.to_u32().to_string()),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -101,11 +121,26 @@ impl Message {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the message is an actually used as Webxdc integration.
|
||||
pub(crate) async fn is_set_as_webxdc_integration(&self, context: &Context) -> Result<bool> {
|
||||
if let Some(integration_id) = context
|
||||
.get_config_parsed::<u32>(Config::WebxdcIntegration)
|
||||
.await?
|
||||
{
|
||||
Ok(integration_id == self.id.to_u32())
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::message;
|
||||
use crate::message::{Message, Viewtype};
|
||||
use crate::test_utils::TestContext;
|
||||
use anyhow::Result;
|
||||
use std::time::Duration;
|
||||
@@ -126,4 +161,65 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_overwrite_default_integration() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let self_chat = &t.get_self_chat().await;
|
||||
assert!(t.init_webxdc_integration(None).await?.is_none());
|
||||
|
||||
async fn assert_integration(t: &Context, name: &str) -> Result<()> {
|
||||
let integration_id = t.init_webxdc_integration(None).await?.unwrap();
|
||||
let integration = Message::load_from_db(t, integration_id).await?;
|
||||
let integration_info = integration.get_webxdc_info(t).await?;
|
||||
assert_eq!(integration_info.name, name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// set default integration
|
||||
let bytes = include_bytes!("../../test-data/webxdc/with-manifest-and-png-icon.xdc");
|
||||
let file = t.get_blobdir().join("maps.xdc");
|
||||
tokio::fs::write(&file, bytes).await.unwrap();
|
||||
t.set_webxdc_integration(file.to_str().unwrap()).await?;
|
||||
assert_integration(&t, "with some icon").await?;
|
||||
|
||||
// send a maps.xdc with insufficient manifest
|
||||
let mut msg = Message::new(Viewtype::Webxdc);
|
||||
msg.set_file_from_bytes(
|
||||
&t,
|
||||
"mapstest.xdc",
|
||||
include_bytes!("../../test-data/webxdc/mapstest-integration-unset.xdc"),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
t.send_msg(self_chat.id, &mut msg).await;
|
||||
assert_integration(&t, "with some icon").await?; // still the default integration
|
||||
|
||||
// send a maps.xdc with manifest including the line `request_integration = "map"`
|
||||
let mut msg = Message::new(Viewtype::Webxdc);
|
||||
msg.set_file_from_bytes(
|
||||
&t,
|
||||
"mapstest.xdc",
|
||||
include_bytes!("../../test-data/webxdc/mapstest-integration-set.xdc"),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let sent = t.send_msg(self_chat.id, &mut msg).await;
|
||||
let info = msg.get_webxdc_info(&t).await?;
|
||||
assert!(info.summary.contains("Used as map"));
|
||||
assert_integration(&t, "Maps Test 2").await?;
|
||||
|
||||
// when maps.xdc is received on another device, the integration is not accepted (needs to be forwarded again)
|
||||
let t2 = TestContext::new_alice().await;
|
||||
let msg2 = t2.recv_msg(&sent).await;
|
||||
let info = msg2.get_webxdc_info(&t2).await?;
|
||||
assert!(info.summary.contains("To use as map,"));
|
||||
assert!(t2.init_webxdc_integration(None).await?.is_none());
|
||||
|
||||
// deleting maps.xdc removes the user's integration - the UI will go back to default calling set_webxdc_integration() then
|
||||
message::delete_msgs(&t, &[msg.id]).await?;
|
||||
assert!(t.init_webxdc_integration(None).await?.is_none());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ mod tests {
|
||||
async fn test_maps_integration() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
|
||||
let bytes = include_bytes!("../../test-data/webxdc/mapstest.xdc");
|
||||
let bytes = include_bytes!("../../test-data/webxdc/mapstest-integration-set.xdc");
|
||||
let file = t.get_blobdir().join("maps.xdc");
|
||||
tokio::fs::write(&file, bytes).await.unwrap();
|
||||
t.set_webxdc_integration(file.to_str().unwrap()).await?;
|
||||
@@ -199,7 +199,7 @@ mod tests {
|
||||
|
||||
let integration = Message::load_from_db(&t, integration_id).await?;
|
||||
let info = integration.get_webxdc_info(&t).await?;
|
||||
assert_eq!(info.name, "Maps Test");
|
||||
assert_eq!(info.name, "Maps Test 2");
|
||||
assert_eq!(info.internet_access, true);
|
||||
|
||||
t.send_webxdc_status_update(
|
||||
|
||||
Reference in New Issue
Block a user