use crate::Audience;
use super::policy::SectorAccessPolicy;
#[derive(Debug, Clone)]
pub struct PolicyDecision {
pub audience: Audience,
pub redacted_fields: Vec<String>,
pub filtered_data: serde_json::Value,
}
pub fn filter_by_audience(
data: &serde_json::Value,
policy: &SectorAccessPolicy,
audience: Audience,
) -> PolicyDecision {
let mut redacted_fields = Vec::new();
let filtered_data = filter_value(data, policy, audience, "", &mut redacted_fields);
PolicyDecision {
audience,
redacted_fields,
filtered_data,
}
}
fn filter_value(
data: &serde_json::Value,
policy: &SectorAccessPolicy,
audience: Audience,
prefix: &str,
redacted: &mut Vec<String>,
) -> serde_json::Value {
match data {
serde_json::Value::Object(map) => {
let mut filtered = serde_json::Map::new();
for (key, value) in map {
let path = if prefix.is_empty() {
key.clone()
} else {
format!("{prefix}.{key}")
};
if audience.may_see(policy.disclosure_for_field(key)) {
filtered.insert(
key.clone(),
filter_value(value, policy, audience, &path, redacted),
);
} else {
redacted.push(path);
}
}
serde_json::Value::Object(filtered)
}
serde_json::Value::Array(items) => serde_json::Value::Array(
items
.iter()
.enumerate()
.map(|(i, v)| {
filter_value(v, policy, audience, &format!("{prefix}[{i}]"), redacted)
})
.collect(),
),
other => other.clone(),
}
}