use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::{SData, SDataRef, SField, SFunc, SGraph, SNodeRef};
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
pub enum Access {
#[default]
None,
Read,
Write,
}
impl Access {
pub fn can_read(&self) -> bool {
match self {
Self::Read |
Self::Write => true,
_ => false,
}
}
pub fn can_write(&self) -> bool {
match self {
Self::Write => true,
_ => false,
}
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct DocPermissions {
pub permissions: Permissions,
}
impl DocPermissions {
pub fn merge(&mut self, other: &Self) {
self.permissions.merge(&other.permissions);
}
pub fn can_read_field(&self, graph: &SGraph, dref: &SDataRef, from: Option<&SNodeRef>) -> bool {
let private_field;
if let Some(field) = SData::get::<SField>(graph, dref) {
private_field = field.attributes.contains_key("private");
} else {
return false;
}
if let Some(data) = dref.data(graph) {
for nref in &data.nodes {
if self.can_read_scope(graph, nref, from) {
if let Some(from_ref) = from {
if private_field && from_ref.id == nref.id {
return true;
} else if !private_field {
return true;
}
} else {
return true;
}
}
}
}
false
}
pub fn can_read_func(&self, graph: &SGraph, dref: &SDataRef, from: Option<&SNodeRef>) -> bool {
let private_func;
if let Some(func) = SData::get::<SFunc>(graph, dref) {
private_func = func.attributes.contains_key("private");
} else {
return false;
}
if let Some(data) = dref.data(graph) {
for nref in &data.nodes {
if self.can_read_scope(graph, nref, from) {
if let Some(from_ref) = from {
if private_func && from_ref.id == nref.id {
return true;
} else if !private_func {
return true;
}
} else {
return true;
}
}
}
}
false
}
pub fn can_write_field(&self, graph: &SGraph, dref: &SDataRef, from: Option<&SNodeRef>) -> bool {
let private_field;
if let Some(field) = SData::get::<SField>(graph, dref) {
if let Some(read_only_val) = field.attributes.get("readonly") {
if read_only_val.is_empty() || read_only_val.truthy() {
return false;
}
}
private_field = field.attributes.contains_key("private");
} else {
return false;
}
if let Some(data) = dref.data(graph) {
for nref in &data.nodes {
if self.can_write_scope(graph, nref, from) {
if let Some(from_ref) = from {
if private_field && from_ref.id == nref.id {
return true;
} else if !private_field {
return true;
}
} else {
return true;
}
}
}
}
false
}
pub fn can_write_func(&self, graph: &SGraph, dref: &SDataRef, from: Option<&SNodeRef>) -> bool {
let private_func;
if let Some(func) = SData::get::<SFunc>(graph, dref) {
private_func = func.attributes.contains_key("private");
} else {
return false;
}
if let Some(data) = dref.data(graph) {
for nref in &data.nodes {
if self.can_write_scope(graph, nref, from) {
if let Some(from_ref) = from {
if private_func && from_ref.id == nref.id {
return true;
} else if !private_func {
return true;
}
} else {
return true;
}
}
}
}
false
}
pub fn can_read_scope(&self, graph: &SGraph, scope: &SNodeRef, from: Option<&SNodeRef>) -> bool {
let access = self.permissions.access(graph, scope, from);
access.can_read()
}
pub fn can_write_scope(&self, graph: &SGraph, scope: &SNodeRef, from: Option<&SNodeRef>) -> bool {
let access = self.permissions.access(graph, scope, from);
access.can_write()
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Permissions {
locked: bool,
pub general: ScopePermissions,
pub scope: HashMap<SNodeRef, ScopePermissions>,
}
impl Permissions {
pub fn merge(&mut self, other: &Self) {
self.general.merge(&other.general);
for (scope, perms) in &other.scope {
if !self.scope.contains_key(scope) {
self.scope.insert(scope.clone(), perms.clone());
}
}
}
pub fn locked() -> Self {
let mut permissions = Self::default();
permissions.locked = true;
permissions
}
pub fn access(&self, graph: &SGraph, scope: &SNodeRef, from: Option<&SNodeRef>) -> Access {
if self.locked {
return Access::None;
}
if let Some(from) = from {
if let Some(from_perms) = self.scope.get(from) {
return from_perms.access(graph, scope);
}
let mut id_path = from.id_path(graph);
id_path.pop();
id_path.reverse();
for nref_id in id_path {
if let Some(perms) = self.scope.get(&SNodeRef::from(nref_id)) {
return perms.access(graph, scope);
}
}
}
self.general.access(graph, scope)
}
pub fn set_general_scope_access_path(&mut self, graph: &SGraph, path: &str, start: Option<&SNodeRef>, access: Access) -> bool {
self.general.set_scope_access_path(graph, path, start, access)
}
pub fn set_general_scope_access(&mut self, scope: SNodeRef, access: Access) {
self.general.set_scope_access(scope, access);
}
pub fn set_scope_access_path_from(&mut self, from: &SNodeRef, graph: &SGraph, path: &str, start: Option<&SNodeRef>, access: Access) -> bool {
if let Some(from_perms) = self.scope.get_mut(from) {
return from_perms.set_scope_access_path(graph, path, start, access);
}
let mut from_perms = ScopePermissions::default();
let res = from_perms.set_scope_access_path(graph, path, start, access);
if res {
self.scope.insert(from.clone(), from_perms);
}
res
}
pub fn set_scope_access_from(&mut self, from: &SNodeRef, scope: SNodeRef, access: Access) {
if let Some(from_perms) = self.scope.get_mut(from) {
from_perms.set_scope_access(scope, access);
} else {
let mut from_perms = ScopePermissions::default();
from_perms.set_scope_access(scope, access);
self.scope.insert(from.clone(), from_perms);
}
}
pub fn set_scope_access_path_from_path(&mut self, graph: &SGraph, from: &str, path: &str, from_start: Option<&SNodeRef>, path_start: Option<&SNodeRef>, access: Access) -> bool {
if let Some(nref) = graph.node_ref(&from.replace('.', "/"), from_start) {
return self.set_scope_access_path_from(&nref, graph, path, path_start, access);
}
false
}
pub fn set_scope_access_from_path(&mut self, graph: &SGraph, from: &str, from_start: Option<&SNodeRef>, scope: SNodeRef, access: Access) -> bool {
if let Some(nref) = graph.node_ref(&from.replace('.', "/"), from_start) {
self.set_scope_access_from(&nref, scope, access);
return true;
}
false
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct ScopePermissions {
pub scopes: HashMap<SNodeRef, Access>,
}
impl ScopePermissions {
pub fn merge(&mut self, other: &Self) {
for (nref, access) in &other.scopes {
if !self.scopes.contains_key(nref) {
self.scopes.insert(nref.clone(), access.clone());
}
}
}
pub fn set_scope_access_path(&mut self, graph: &SGraph, path: &str, start: Option<&SNodeRef>, access: Access) -> bool {
if let Some(nref) = graph.node_ref(&path.replace('.', "/"), start) {
self.scopes.insert(nref, access);
return true;
}
false
}
pub fn set_scope_access(&mut self, scope: SNodeRef, access: Access) {
self.scopes.insert(scope, access);
}
pub fn access(&self, graph: &SGraph, scope: &SNodeRef) -> Access {
if let Some(access) = self.scopes.get(scope) {
return *access;
}
let mut id_path = scope.id_path(graph);
id_path.pop(); id_path.reverse();
for nref_id in id_path {
if let Some(access) = self.scopes.get(&SNodeRef::from(nref_id)) {
return *access;
}
}
Access::Write
}
}