use crate::{
capabilities_to_statement, translation::ToResource, Capability, Error, Namespace, Set,
};
use std::collections::{BTreeMap, HashMap};
use iri_string::types::UriString;
use serde_json::Value;
use siwe::Message;
#[derive(Default, Debug)]
pub struct Builder {
capabilities: BTreeMap<Namespace, Capability>,
}
impl Builder {
pub fn new() -> Builder {
Builder::default()
}
pub fn default_actions(&self, namespace: &Namespace) -> Option<&Set<String>> {
self.capabilities
.get(namespace)
.as_ref()
.map(|cap| &cap.default_actions)
}
pub fn actions(&self, namespace: &Namespace) -> Option<&BTreeMap<String, Set<String>>> {
self.capabilities
.get(namespace)
.as_ref()
.map(|cap| &cap.targeted_actions)
}
pub fn extra_fields(&self, namespace: &Namespace) -> Option<&HashMap<String, Value>> {
self.capabilities
.get(namespace)
.as_ref()
.map(|cap| &cap.extra_fields)
}
pub fn with_default_action<S>(mut self, namespace: &Namespace, action: S) -> Self
where
S: Into<String>,
{
self.namespace(namespace).default_actions.insert(action);
self
}
pub fn with_default_actions<I, S>(mut self, namespace: &Namespace, actions: I) -> Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.namespace(namespace)
.default_actions
.insert_all(actions);
self
}
pub fn with_action<T, S>(mut self, namespace: &Namespace, target: T, action: S) -> Self
where
T: Into<String>,
S: Into<String>,
{
let target = target.into();
if let Some(actions) = self.namespace(namespace).targeted_actions.get_mut(&target) {
actions.insert(action);
} else {
self.namespace(namespace)
.targeted_actions
.insert(target, Set::from_iter([action]));
}
self
}
pub fn with_actions<I, S, T>(mut self, namespace: &Namespace, target: T, actions: I) -> Self
where
T: Into<String>,
S: Into<String>,
I: IntoIterator<Item = S>,
{
let target = target.into();
if let Some(current_actions) = self.namespace(namespace).targeted_actions.get_mut(&target) {
current_actions.insert_all(actions);
} else {
self.namespace(namespace)
.targeted_actions
.insert(target, Set::from_iter(actions));
}
self
}
pub fn with_extra_fields(
mut self,
namespace: &Namespace,
fields: HashMap<String, Value>,
) -> Self {
self.namespace(namespace).extra_fields.extend(fields);
self
}
pub fn build(&self, mut message: Message) -> Result<Message, Error> {
let statement = self.statement(&message.uri);
let resources = self
.capabilities
.iter()
.map(|cap| cap.to_resource())
.collect::<Result<Vec<UriString>, Error>>()?;
message.statement = match (message.statement, statement) {
(s, None) => s,
(None, s) => s,
(Some(s), Some(t)) => Some(format!("{} {}", s, t)),
};
message.resources.extend(resources);
Ok(message)
}
pub fn statement(&self, uri: &UriString) -> Option<String> {
capabilities_to_statement(&self.capabilities, uri)
}
fn namespace(&mut self, namespace: &Namespace) -> &mut Capability {
if !self.capabilities.contains_key(namespace) {
self.capabilities
.insert(namespace.clone(), Capability::default());
}
self.capabilities.get_mut(namespace).unwrap()
}
}