Merge pull request 'Mail rules: group and tenant ids in their JMAP form' (#112) from feature/rule-ids-as-jmap-ids into main
This commit was merged in pull request #112.
This commit is contained in:
@@ -60,6 +60,41 @@ fn one() -> u32 {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Group and tenant ids in the JMAP form clients use (`"b"`, `"c"`…), held
|
||||||
|
/// as numbers for matching. Plain numbers are read too.
|
||||||
|
mod jmap_ids {
|
||||||
|
use serde::{Deserialize, Deserializer, Serializer, de::Error, ser::SerializeSeq};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use types::id::Id;
|
||||||
|
|
||||||
|
pub fn serialize<S: Serializer>(ids: &[u32], serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let mut seq = serializer.serialize_seq(Some(ids.len()))?;
|
||||||
|
for id in ids {
|
||||||
|
seq.serialize_element(&Id::from(*id).to_string())?;
|
||||||
|
}
|
||||||
|
seq.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Either {
|
||||||
|
Text(String),
|
||||||
|
Number(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u32>, D::Error> {
|
||||||
|
Vec::<Either>::deserialize(deserializer)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|id| match id {
|
||||||
|
Either::Number(n) => Ok(n),
|
||||||
|
Either::Text(text) => Id::from_str(&text)
|
||||||
|
.map(|id| id.document_id())
|
||||||
|
.map_err(|_| D::Error::custom(format!("\"{text}\" isn't an id"))),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A detector and the least it must find.
|
/// A detector and the least it must find.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, SerdeSerialize, SerdeDeserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, SerdeSerialize, SerdeDeserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -83,9 +118,11 @@ pub enum Condition {
|
|||||||
domains: Vec<String>,
|
domains: Vec<String>,
|
||||||
},
|
},
|
||||||
SenderGroup {
|
SenderGroup {
|
||||||
|
#[serde(with = "jmap_ids")]
|
||||||
groups: Vec<u32>,
|
groups: Vec<u32>,
|
||||||
},
|
},
|
||||||
SenderTenant {
|
SenderTenant {
|
||||||
|
#[serde(with = "jmap_ids")]
|
||||||
tenants: Vec<u32>,
|
tenants: Vec<u32>,
|
||||||
},
|
},
|
||||||
/// Any recipient is one of these.
|
/// Any recipient is one of these.
|
||||||
@@ -96,6 +133,7 @@ pub enum Condition {
|
|||||||
domains: Vec<String>,
|
domains: Vec<String>,
|
||||||
},
|
},
|
||||||
RecipientGroup {
|
RecipientGroup {
|
||||||
|
#[serde(with = "jmap_ids")]
|
||||||
groups: Vec<u32>,
|
groups: Vec<u32>,
|
||||||
},
|
},
|
||||||
/// Any recipient isn't at a domain this server hosts.
|
/// Any recipient isn't at a domain this server hosts.
|
||||||
@@ -609,6 +647,21 @@ mod tests {
|
|||||||
assert_eq!(back["actions"][0]["notifySender"], true);
|
assert_eq!(back["actions"][0]["notifySender"], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn group_and_tenant_ids_are_jmap_ids() {
|
||||||
|
let condition: Condition =
|
||||||
|
serde_json::from_str(r#"{"type":"senderGroup","groups":["b", 7]}"#).unwrap();
|
||||||
|
assert_eq!(condition, Condition::SenderGroup { groups: vec![1, 7] });
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_value(&condition).unwrap()["groups"],
|
||||||
|
serde_json::json!(["b", "h"])
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
serde_json::from_str::<Condition>(r#"{"type":"senderTenant","tenants":["!!"]}"#)
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dlp_rules_have_one_dlp_action_on_outgoing_mail() {
|
fn dlp_rules_have_one_dlp_action_on_outgoing_mail() {
|
||||||
let block = Action::Block {
|
let block = Action::Block {
|
||||||
|
|||||||
@@ -114,6 +114,33 @@ pub async fn test(test: &mut TestServer) {
|
|||||||
"{rule}"
|
"{rule}"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Group and tenant ids travel in their JMAP form
|
||||||
|
let mut by_tenant = transport_rule();
|
||||||
|
by_tenant["name"] = "By tenant".into();
|
||||||
|
by_tenant["conditions"] = json!([{"type": "senderTenant", "tenants": ["b"]}]);
|
||||||
|
let (_, response) = call(
|
||||||
|
&admin,
|
||||||
|
"inbuxa:MailRule/set",
|
||||||
|
json!({"create": {"g": by_tenant}}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let tenant_rule = response["created"]["g"]["id"]
|
||||||
|
.as_str()
|
||||||
|
.unwrap_or_else(|| panic!("{response}"))
|
||||||
|
.to_string();
|
||||||
|
let (_, response) = call(&admin, "inbuxa:MailRule/get", json!({"ids": [tenant_rule]})).await;
|
||||||
|
assert_eq!(
|
||||||
|
response["list"][0]["conditions"][0]["tenants"],
|
||||||
|
json!(["b"]),
|
||||||
|
"{response}"
|
||||||
|
);
|
||||||
|
call(
|
||||||
|
&admin,
|
||||||
|
"inbuxa:MailRule/set",
|
||||||
|
json!({"destroy": [tenant_rule]}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Checked when written
|
// Checked when written
|
||||||
let mut inbound = dlp_rule();
|
let mut inbound = dlp_rule();
|
||||||
inbound["direction"] = "incoming".into();
|
inbound["direction"] = "incoming".into();
|
||||||
|
|||||||
Reference in New Issue
Block a user