use serde_json::{Value, json};
use uuid::Uuid;
use crate::errors::ConsentRequiredError;
pub const DEFAULT_CONSENT_MESSAGE: &str = "Consent is required to proceed";
pub const UNKNOWN_SERVICE_ID: &str = "unknown_service";
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct UrlElicitationPayload {
pub message: String,
pub data: Value,
}
pub fn build_url_elicitation_payload(
consent: &ConsentRequiredError,
) -> Option<UrlElicitationPayload> {
let consent_url = consent.consent_url.as_ref()?;
let message = if consent.message.is_empty() {
DEFAULT_CONSENT_MESSAGE.to_string()
} else {
consent.message.clone()
};
let service_id = if consent.service_id.is_empty() {
UNKNOWN_SERVICE_ID.to_string()
} else {
consent.service_id.clone()
};
let cause_detail = if consent.cause_detail.is_empty() {
message.clone()
} else {
consent.cause_detail.clone()
};
let data = json!({
"elicitations": [{
"mode": "url",
"url": consent_url,
"elicitationId": Uuid::new_v4().to_string(),
"message": format!("{message} ({service_id}: {cause_detail})"),
}]
});
Some(UrlElicitationPayload { message, data })
}
#[cfg(test)]
mod tests {
use super::*;
fn consent(
url: Option<&str>,
message: &str,
service_id: &str,
cause: &str,
) -> ConsentRequiredError {
ConsentRequiredError {
message: message.to_string(),
code: "consent_required".to_string(),
status_code: Some(400),
service_id: service_id.to_string(),
cause_detail: cause.to_string(),
consent_url: url.map(ToString::to_string),
}
}
#[test]
fn returns_none_when_consent_url_missing() {
let result = build_url_elicitation_payload(&consent(None, "msg", "svc", "cause"));
assert!(result.is_none());
}
#[test]
fn populates_payload_with_supplied_fields() {
let payload = build_url_elicitation_payload(&consent(
Some("https://example.com/consent"),
"Approve to continue",
"drive",
"approval_pending",
))
.expect("payload");
assert_eq!(payload.message, "Approve to continue");
let data = payload.data;
assert_eq!(data["elicitations"][0]["mode"], "url");
assert_eq!(
data["elicitations"][0]["url"],
"https://example.com/consent"
);
let msg = data["elicitations"][0]["message"]
.as_str()
.expect("message");
assert!(msg.contains("Approve to continue"));
assert!(msg.contains("drive"));
assert!(msg.contains("approval_pending"));
let id = data["elicitations"][0]["elicitationId"]
.as_str()
.expect("elicitationId");
Uuid::parse_str(id).expect("valid uuid");
}
#[test]
fn applies_defaults_for_blank_fields() {
let payload = build_url_elicitation_payload(&consent(
Some("https://example.com/consent"),
"",
"",
"",
))
.expect("payload");
assert_eq!(payload.message, DEFAULT_CONSENT_MESSAGE);
let msg = payload.data["elicitations"][0]["message"]
.as_str()
.expect("message");
assert!(msg.contains(UNKNOWN_SERVICE_ID));
assert!(msg.contains(DEFAULT_CONSENT_MESSAGE));
}
}