use crate::fault::Fault;
use hl7_2_xml_lite_helper::Element;
#[must_use]
pub fn interaction_id(payload: &Element) -> &str {
payload.local_name()
}
#[must_use]
pub fn control_id(payload: &Element) -> Option<&str> {
payload.child("id")?.attribute("extension")
}
#[must_use]
pub fn assigning_authority(payload: &Element) -> Option<&str> {
payload
.child("id")
.and_then(|id| id.attribute("root"))
.or_else(|| {
payload
.child("sender")
.and_then(|sender| sender.child("device"))
.and_then(|device| device.child("id"))
.and_then(|id| id.attribute("root"))
})
}
pub fn check(
payload: &Element,
allowed_interactions: &[String],
allowed_authorities: &[String],
) -> Result<(), Fault> {
let interaction = interaction_id(payload);
if !allowed_interactions.is_empty() && !allowed_interactions.iter().any(|a| a == interaction) {
return Err(Fault::validation(format!(
"Unsupported HL7 v3 interaction '{interaction}'. Allowed values: {}",
listed(allowed_interactions)
)));
}
if !allowed_authorities.is_empty() {
let authority = assigning_authority(payload).ok_or_else(|| {
Fault::validation("Unable to determine assigning authority from payload.")
})?;
if !allowed_authorities.iter().any(|a| a == authority) {
return Err(Fault::authorization(format!(
"Assigning authority '{authority}' is not authorised. Allowed values: {}",
listed(allowed_authorities)
)));
}
}
Ok(())
}
fn listed(values: &[String]) -> String {
let mut sorted: Vec<&str> = values.iter().map(String::as_str).collect();
sorted.sort_unstable();
sorted.join(", ")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse;
fn payload_of(xml_text: &str) -> Element {
parse(xml_text).unwrap().payload().unwrap().clone()
}
const V3_MESSAGE: &str = r#"<Envelope><Body>
<PRPA_IN201305UV02>
<id root="2.16.840.1.113883.19.5" extension="CTRL7"/>
<sender><device><id root="2.16.840.1.113883.19.6"/></device></sender>
</PRPA_IN201305UV02></Body></Envelope>"#;
#[test]
fn reads_a_v3_payload() {
let payload = payload_of(V3_MESSAGE);
assert_eq!(interaction_id(&payload), "PRPA_IN201305UV02");
assert_eq!(control_id(&payload), Some("CTRL7"));
assert_eq!(
assigning_authority(&payload),
Some("2.16.840.1.113883.19.5")
);
}
#[test]
fn falls_through_to_the_sender_device_when_the_message_has_no_root() {
let from_sender = payload_of(
r#"<Envelope><Body><PRPA_IN201305UV02>
<sender><device><id root="2.16.840.1.113883.19.6"/></device></sender>
</PRPA_IN201305UV02></Body></Envelope>"#,
);
assert_eq!(
assigning_authority(&from_sender),
Some("2.16.840.1.113883.19.6")
);
let from_nowhere = payload_of(r#"<Envelope><Body><PRPA_IN201305UV02/></Body></Envelope>"#);
assert_eq!(assigning_authority(&from_nowhere), None);
}
#[test]
fn checks_the_interaction_and_the_authority() {
let payload = payload_of(V3_MESSAGE);
let interactions = vec!["PRPA_IN201305UV02".to_string()];
let authorities = vec!["2.16.840.1.113883.19.5".to_string()];
assert!(check(&payload, &interactions, &authorities).is_ok());
assert!(check(&payload, &[], &[]).is_ok());
let wrong_interaction =
check(&payload, &["PRPA_IN201306UV02".to_string()], &authorities).unwrap_err();
assert_eq!(wrong_interaction.status, 400);
assert!(wrong_interaction.reason.contains("PRPA_IN201305UV02"));
let wrong_authority = check(&payload, &interactions, &["9.9.9".to_string()]).unwrap_err();
assert_eq!(
wrong_authority.status, 403,
"not authorised is not a validation error"
);
}
#[test]
fn a_payload_with_no_authority_cannot_be_authorised() {
let payload = payload_of(r#"<Envelope><Body><PRPA_IN201305UV02/></Body></Envelope>"#);
let error = check(&payload, &[], &["2.16.840.1.113883.19.5".to_string()]).unwrap_err();
assert!(
error
.reason
.contains("Unable to determine assigning authority")
);
}
}