use serde_json::{json, Map, Value};
use crate::error::Result;
use crate::transport::{RequestOptions, Transport};
use crate::types::{SurveyAnswer, SurveyContext, SurveyListItem};
#[derive(Debug, Clone, Copy)]
enum Action {
Start,
Partial,
Submit,
Abandon,
}
impl Action {
fn as_str(&self) -> &'static str {
match self {
Action::Start => "start",
Action::Partial => "partial",
Action::Submit => "submit",
Action::Abandon => "abandon",
}
}
}
pub struct Surveys {
transport: Transport,
api_key: String,
}
impl Surveys {
pub fn new(transport: Transport, api_key: String) -> Self {
Self { transport, api_key }
}
fn auth(&self) -> (String, String) {
("x-api-key".to_string(), self.api_key.clone())
}
pub fn list(
&self,
distinct_id: Option<&str>,
anonymous_id: Option<&str>,
) -> Result<Vec<SurveyListItem>> {
let mut body = Map::new();
body.insert("api_key".to_string(), json!(self.api_key));
if let Some(c) = distinct_id {
body.insert("customer_id".to_string(), json!(c));
}
if let Some(a) = anonymous_id {
body.insert("anonymous_id".to_string(), json!(a));
}
let (hk, hv) = self.auth();
let opts = RequestOptions::post("/bdsurvey-list", Value::Object(body))
.header(hk, hv)
.gzip(false);
let data = self.transport.request(&opts)?;
let surveys = data
.get("surveys")
.and_then(|v| serde_json::from_value(v.clone()).ok())
.unwrap_or_default();
Ok(surveys)
}
pub fn fetch(
&self,
survey_id: &str,
distinct_id: Option<&str>,
anonymous_id: Option<&str>,
) -> Result<Value> {
let mut body = Map::new();
body.insert("api_key".to_string(), json!(self.api_key));
body.insert("survey_id".to_string(), json!(survey_id));
if let Some(c) = distinct_id {
body.insert("customer_id".to_string(), json!(c));
}
if let Some(a) = anonymous_id {
body.insert("anonymous_id".to_string(), json!(a));
}
let (hk, hv) = self.auth();
let opts = RequestOptions::post("/bdsurvey-fetch", Value::Object(body))
.header(hk, hv)
.gzip(false);
self.transport.request(&opts)
}
pub fn start(&self, survey_id: &str, context: &SurveyContext) -> Result<Value> {
self.submit_request(Action::Start, survey_id, None, context)
}
pub fn record_partial(
&self,
survey_id: &str,
respondent_id: &str,
answers: &[SurveyAnswer],
context: &SurveyContext,
) -> Result<Value> {
let mut ctx = context.clone();
ctx.respondent_id = Some(respondent_id.to_string());
self.submit_request(Action::Partial, survey_id, Some(answers), &ctx)
}
pub fn submit(
&self,
survey_id: &str,
answers: &[SurveyAnswer],
context: &SurveyContext,
) -> Result<Value> {
self.submit_request(Action::Submit, survey_id, Some(answers), context)
}
pub fn abandon(&self, survey_id: &str, respondent_id: &str) -> Result<Value> {
let ctx = SurveyContext {
respondent_id: Some(respondent_id.to_string()),
..Default::default()
};
self.submit_request(Action::Abandon, survey_id, None, &ctx)
}
fn submit_request(
&self,
action: Action,
survey_id: &str,
answers: Option<&[SurveyAnswer]>,
context: &SurveyContext,
) -> Result<Value> {
let body = self.build_body(action, survey_id, answers, context);
let (hk, hv) = self.auth();
let opts = RequestOptions::post("/bdsurvey-submit", body)
.header(hk, hv)
.gzip(false);
self.transport.request(&opts)
}
fn build_body(
&self,
action: Action,
survey_id: &str,
answers: Option<&[SurveyAnswer]>,
ctx: &SurveyContext,
) -> Value {
let mut body = Map::new();
body.insert("action".to_string(), json!(action.as_str()));
body.insert("api_key".to_string(), json!(self.api_key));
body.insert("survey_id".to_string(), json!(survey_id));
if let Some(a) = answers {
body.insert("answers".to_string(), json!(a));
}
if let Some(v) = &ctx.respondent_id {
body.insert("respondent_id".to_string(), json!(v));
}
if let Some(v) = &ctx.customer_id {
body.insert("customer_id".to_string(), json!(v));
}
if let Some(v) = &ctx.anonymous_id {
body.insert("anonymous_id".to_string(), json!(v));
}
if let Some(v) = &ctx.session_id {
body.insert("session_id".to_string(), json!(v));
}
if let Some(v) = &ctx.platform {
body.insert("platform".to_string(), json!(v));
}
if let Some(v) = &ctx.device_info {
body.insert("device_info".to_string(), Value::Object(v.clone()));
}
if let Some(v) = ctx.duration_ms {
body.insert("duration_ms".to_string(), json!(v));
}
if let Some(v) = &ctx.context {
body.insert("context".to_string(), Value::Object(v.clone()));
}
if let Some(v) = &ctx.collector_id {
body.insert("collector_id".to_string(), json!(v));
}
if let Some(v) = &ctx.collector_type {
body.insert("collector_type".to_string(), json!(v));
}
if let Some(v) = &ctx.idempotency_key {
body.insert("idempotency_key".to_string(), json!(v));
}
Value::Object(body)
}
}