use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "ts-export", derive(ts_rs::TS), ts(export))]
pub struct PairingChannelsRequest {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub locale: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "ts-export", derive(ts_rs::TS), ts(export))]
pub struct PairingChannelsResponse {
pub channels: Vec<PairingChannelInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "ts-export", derive(ts_rs::TS), ts(export))]
pub struct PairingChannelInfo {
pub channel: String,
pub kind: PairingChannelKind,
pub label: String,
#[serde(default)]
pub instructions: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub fields: Vec<PairingChannelField>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub linked_instances: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub notify_method: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub instance_field: Option<String>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "ts-export", derive(ts_rs::TS), ts(export))]
#[serde(rename_all = "snake_case")]
pub enum PairingChannelKind {
Qr,
Form,
Info,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "ts-export", derive(ts_rs::TS), ts(export))]
pub struct PairingChannelField {
pub name: String,
pub label: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub help: Option<String>,
pub sensitive: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub placeholder: Option<String>,
pub required: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_response_round_trips() {
let r = PairingChannelsResponse::default();
let v = serde_json::to_value(&r).unwrap();
let back: PairingChannelsResponse = serde_json::from_value(v).unwrap();
assert_eq!(r, back);
}
#[test]
fn qr_channel_round_trips() {
let r = PairingChannelsResponse {
channels: vec![PairingChannelInfo {
channel: "whatsapp".into(),
kind: PairingChannelKind::Qr,
label: "WhatsApp".into(),
instructions: "Open WhatsApp → ...".into(),
fields: vec![],
linked_instances: vec!["549@s.whatsapp.net".into()],
notify_method: None,
instance_field: None,
}],
};
let v = serde_json::to_value(&r).unwrap();
let back: PairingChannelsResponse = serde_json::from_value(v).unwrap();
assert_eq!(r, back);
}
#[test]
fn form_channel_round_trips() {
let r = PairingChannelsResponse {
channels: vec![PairingChannelInfo {
channel: "telegram".into(),
kind: PairingChannelKind::Form,
label: "Telegram".into(),
instructions: "Paste your bot token.".into(),
fields: vec![
PairingChannelField {
name: "instance".into(),
label: "Bot username".into(),
help: None,
sensitive: false,
placeholder: Some("mi_bot".into()),
required: true,
},
PairingChannelField {
name: "token".into(),
label: "Bot token".into(),
help: None,
sensitive: true,
placeholder: None,
required: true,
},
],
linked_instances: vec![],
notify_method: None,
instance_field: None,
}],
};
let v = serde_json::to_value(&r).unwrap();
let back: PairingChannelsResponse = serde_json::from_value(v).unwrap();
assert_eq!(r, back);
}
#[test]
fn skip_serializing_keeps_payload_small() {
let r = PairingChannelsResponse {
channels: vec![PairingChannelInfo {
channel: "whatsapp".into(),
kind: PairingChannelKind::Qr,
label: "WhatsApp".into(),
instructions: String::new(),
fields: vec![],
linked_instances: vec![],
notify_method: None,
instance_field: None,
}],
};
let v = serde_json::to_value(&r).unwrap();
let obj = v["channels"][0].as_object().unwrap();
assert!(!obj.contains_key("fields"));
assert!(!obj.contains_key("linked_instances"));
assert!(!obj.contains_key("notify_method"));
}
#[test]
fn kind_serialises_snake_case() {
assert_eq!(
serde_json::to_value(PairingChannelKind::Qr).unwrap(),
serde_json::json!("qr")
);
assert_eq!(
serde_json::to_value(PairingChannelKind::Custom).unwrap(),
serde_json::json!("custom")
);
}
}