use crate::rest_api::Method;
use super::Permission;
#[derive(Default)]
pub(in crate::rest_api) struct PermissionMap {
internal: Vec<(RequestDefinition, Permission)>,
}
impl PermissionMap {
pub fn new() -> Self {
Self::default()
}
pub fn permissions(&self) -> impl Iterator<Item = Permission> + '_ {
self.internal.iter().map(|(_, perm)| *perm)
}
pub fn add_permission(&mut self, method: Method, endpoint: &str, permission: Permission) {
self.internal
.push((RequestDefinition::new(method, endpoint), permission));
}
pub fn get_permission(&self, method: &Method, endpoint: &str) -> Option<&Permission> {
self.internal
.iter()
.find(|(req, _)| req.matches(method, endpoint))
.map(|(_, perm)| perm)
}
pub fn append(&mut self, other: &mut PermissionMap) {
self.internal.append(&mut other.internal)
}
}
struct RequestDefinition {
method: Method,
path: Vec<PathComponent>,
}
impl RequestDefinition {
pub fn new(method: Method, endpoint: &str) -> Self {
let path = endpoint
.strip_prefix('/')
.unwrap_or(endpoint)
.split('/')
.map(PathComponent::from)
.collect();
Self { method, path }
}
pub fn matches(&self, method: &Method, endpoint: &str) -> bool {
let components = endpoint
.strip_prefix('/')
.unwrap_or(endpoint)
.split('/')
.collect::<Vec<_>>();
method == &self.method
&& self.path.len() == components.len()
&& components.iter().enumerate().all(|(idx, component)| {
self.path
.get(idx)
.map(|path_component| path_component == component)
.unwrap_or(false)
})
}
}
#[derive(PartialEq)]
enum PathComponent {
Text(String),
Variable,
}
impl From<&str> for PathComponent {
fn from(component: &str) -> Self {
if component.starts_with('{') && component.ends_with('}') {
PathComponent::Variable
} else {
PathComponent::Text(component.into())
}
}
}
impl PartialEq<&str> for PathComponent {
fn eq(&self, other: &&str) -> bool {
match self {
PathComponent::Variable => true,
PathComponent::Text(component) => other == component,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn path_component_parse() {
assert!(PathComponent::from("") == PathComponent::Text("".into()));
assert!(PathComponent::from("test") == PathComponent::Text("test".into()));
assert!(PathComponent::from("{test}") == PathComponent::Variable);
}
#[test]
fn path_component_str_comparison() {
assert!(PathComponent::Variable == "test1");
assert!(PathComponent::Variable == "test2");
assert!(PathComponent::Text("test1".into()) == "test1");
assert!(PathComponent::Text("test1".into()) != "test2");
}
#[test]
fn request_definition() {
let definition = RequestDefinition::new(Method::Get, "/test/endpoint");
assert!(definition.matches(&Method::Get, "/test/endpoint"));
assert!(!definition.matches(&Method::Put, "/test/endpoint"));
assert!(!definition.matches(&Method::Get, "/test/other"));
assert!(!definition.matches(&Method::Get, "/test"));
assert!(!definition.matches(&Method::Get, "/test/endpoint/test"));
let definition = RequestDefinition::new(Method::Get, "/test/endpoint/{variable}");
assert!(definition.matches(&Method::Get, "/test/endpoint/val1"));
assert!(definition.matches(&Method::Get, "/test/endpoint/val2"));
assert!(!definition.matches(&Method::Put, "/test/endpoint/val1"));
let definition = RequestDefinition::new(Method::Get, "/");
assert!(definition.matches(&Method::Get, "/"));
}
#[test]
fn permission_map() {
let perm1 = Permission::Check {
permission_id: "perm1",
permission_display_name: "",
permission_description: "",
};
let perm2 = Permission::Check {
permission_id: "perm2",
permission_display_name: "",
permission_description: "",
};
let mut map = PermissionMap::new();
assert!(map.internal.is_empty());
map.add_permission(Method::Get, "/test/endpoint", perm1);
assert_eq!(map.internal.len(), 1);
assert_eq!(
map.get_permission(&Method::Get, "/test/endpoint"),
Some(&perm1)
);
assert_eq!(map.get_permission(&Method::Put, "/test/endpoint"), None);
assert_eq!(map.get_permission(&Method::Get, "/test/other"), None);
let mut other_map = PermissionMap::new();
other_map.add_permission(Method::Put, "/test/endpoint/{variable}", perm2);
map.append(&mut other_map);
assert_eq!(map.internal.len(), 2);
assert_eq!(
map.get_permission(&Method::Get, "/test/endpoint"),
Some(&perm1)
);
assert_eq!(
map.get_permission(&Method::Put, "/test/endpoint/test1"),
Some(&perm2)
);
assert_eq!(
map.get_permission(&Method::Put, "/test/endpoint/test2"),
Some(&perm2)
);
assert_eq!(
map.get_permission(&Method::Get, "/test/endpoint/test1"),
None
);
}
}