use serde_json::{json, Map, Value};
use crate::core::voiceflow::dialog_blocks::enums::VoiceflowButtonActionType;
use crate::core::voiceflow::dialog_blocks::traits::FromValue;
use crate::core::voiceflow::dialog_blocks::VoiceflowText;
use crate::errors::{VoiceflousionError, VoiceflousionResult};
#[derive(Debug, Clone)]
pub struct VoiceflowButton {
action_type: VoiceflowButtonActionType,
name: String,
payload: Value,
}
impl VoiceflowButton {
pub fn new(name: String, payload: Value, option_url: Option<String>) -> Self {
let action_type = if let Some(url) = option_url {
VoiceflowButtonActionType::Url(url)
} else {
VoiceflowButtonActionType::Path
};
Self {
name,
action_type,
payload,
}
}
pub fn name(&self) -> &String {
&self.name
}
pub fn payload(&self) -> &Value {
&self.payload
}
pub fn get_url_text(&self) -> Option<VoiceflowText> {
match &self.action_type {
VoiceflowButtonActionType::Url(url) => Some(VoiceflowText::new(url.clone())),
_ => None,
}
}
}
impl FromValue for VoiceflowButton {
fn from_value(value: &Value) -> VoiceflousionResult<Option<Self>> {
let name = value.get("name")
.and_then(|name| name.as_str())
.ok_or_else(|| VoiceflousionError::VoiceflowBlockConvertationError(
"VoiceflowButton button name".to_string(),
value.clone()
))?
.to_string();
let request = value.get("request")
.ok_or_else(|| VoiceflousionError::VoiceflowBlockConvertationError(
"VoiceflowButton button request".to_string(),
value.clone()
))?;
let path = request.get("type")
.and_then(|path| path.as_str())
.ok_or_else(|| VoiceflousionError::VoiceflowBlockConvertationError(
"VoiceflowButton button path".to_string(),
value.clone()
))?
.to_string();
let request_payload = request.get("payload")
.ok_or_else(|| VoiceflousionError::VoiceflowBlockConvertationError(
"VoiceflowButton button payload".to_string(),
value.clone()
))?;
let mut payload = extract_payload(request_payload);
payload.as_object_mut().unwrap().insert("path".to_string(), json!(path));
let mut option_url = None;
if let Some(actions_value) = request_payload.get("actions") {
let actions = actions_value.as_array().ok_or_else(|| VoiceflousionError::VoiceflowBlockConvertationError(
"VoiceflowButton button actions".to_string(),
value.clone()
))?;
if let Some(action) = actions.iter().find(|action| {
action.get("type")
.and_then(|action_type| action_type.as_str())
.map(|action_type| action_type == "open_url")
.unwrap_or(false)
}) {
option_url = Some(action["payload"].get("url")
.and_then(|url| url.as_str())
.ok_or_else(|| VoiceflousionError::VoiceflowBlockConvertationError(
"VoiceflowButton button url".to_string(),
value.clone()
))?
.to_string());
}
}
Ok(Some(Self::new(name, payload, option_url)))
}
}
fn extract_payload(payload: &Value) -> Value {
if let Some(obj) = payload.as_object() {
let mut new_obj = Map::new();
for (key, value) in obj {
if key != "actions" && key != "label" {
new_obj.insert(key.clone(), value.clone());
}
}
Value::Object(new_obj)
} else {
Value::Null
}
}