use crate::session::transaction_state::SessionTransactionState;
use crate::storage::{GraphCache, StorageManager, Value};
use crate::txn::TransactionManager;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Clone, Default)]
pub struct SessionPermissionCache {}
impl SessionPermissionCache {
pub fn new() -> Self {
Self {}
}
pub fn can_access_graph(&self, _graph_name: &str, _action: &str) -> bool {
true }
pub fn can_access_schema(&self, _schema_name: &str, _action: &str) -> bool {
true }
pub fn can_perform_operation(&self, _operation: &str) -> bool {
true }
}
#[derive(Clone)]
pub struct UserSession {
pub session_id: String,
pub user_id: String,
pub username: String,
pub roles: Vec<String>,
pub current_graph: Option<String>,
pub current_schema: Option<String>,
pub current_timezone: Option<String>,
pub parameters: HashMap<String, Value>,
pub permissions: SessionPermissionCache,
pub transaction_state: Arc<SessionTransactionState>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub last_activity: chrono::DateTime<chrono::Utc>,
pub active: bool,
}
impl UserSession {
pub fn new(
username: String,
roles: Vec<String>,
permissions: SessionPermissionCache,
transaction_manager: Arc<TransactionManager>,
) -> Self {
let now = chrono::Utc::now();
let session_id = uuid::Uuid::new_v4().to_string();
let transaction_state = Arc::new(SessionTransactionState::new(transaction_manager));
Self {
session_id,
user_id: username.clone(), username,
roles,
current_graph: None,
current_schema: None,
current_timezone: None,
parameters: HashMap::new(),
permissions,
transaction_state,
created_at: now,
last_activity: now,
active: true,
}
}
pub fn set_current_graph(&mut self, graph_path: Option<String>) {
self.current_graph = graph_path;
self.update_activity();
}
pub fn get_current_graph(&self) -> Option<&String> {
self.current_graph.as_ref()
}
pub fn clear_current_graph(&mut self) {
self.current_graph = None;
self.update_activity();
}
pub fn set_current_schema(&mut self, schema: Option<String>) {
self.current_schema = schema;
self.update_activity();
}
pub fn get_current_schema(&self) -> Option<&String> {
self.current_schema.as_ref()
}
pub fn set_current_timezone(&mut self, timezone: Option<String>) {
self.current_timezone = timezone;
self.update_activity();
}
pub fn get_current_timezone(&self) -> Option<&String> {
self.current_timezone.as_ref()
}
pub fn set_parameter(&mut self, key: String, value: Value) {
self.parameters.insert(key, value);
self.update_activity();
}
pub fn get_parameter(&self, key: &str) -> Option<&Value> {
self.parameters.get(key)
}
pub fn remove_parameter(&mut self, key: &str) -> Option<Value> {
self.update_activity();
self.parameters.remove(key)
}
pub fn clear_parameters(&mut self) {
self.parameters.clear();
self.update_activity();
}
pub fn set_schema_enforcement_mode(&mut self, mode: &str) {
self.set_parameter(
"schema_enforcement_mode".to_string(),
Value::String(mode.to_string()),
);
}
pub fn get_schema_enforcement_mode(&self) -> &str {
self.get_parameter("schema_enforcement_mode")
.and_then(|v| match v {
Value::String(s) => Some(s.as_str()),
_ => None,
})
.unwrap_or("advisory")
}
pub fn set_validate_on_write(&mut self, enabled: bool) {
self.set_parameter(
"schema_validate_on_write".to_string(),
Value::Boolean(enabled),
);
}
pub fn get_validate_on_write(&self) -> bool {
self.get_parameter("schema_validate_on_write")
.and_then(|v| match v {
Value::Boolean(b) => Some(*b),
_ => None,
})
.unwrap_or(true)
}
pub fn set_allow_unknown_properties(&mut self, allow: bool) {
self.set_parameter(
"schema_allow_unknown_properties".to_string(),
Value::Boolean(allow),
);
}
pub fn get_allow_unknown_properties(&self) -> bool {
self.get_parameter("schema_allow_unknown_properties")
.and_then(|v| match v {
Value::Boolean(b) => Some(*b),
_ => None,
})
.unwrap_or_else(|| self.get_schema_enforcement_mode() != "strict")
}
pub fn update_activity(&mut self) {
self.last_activity = chrono::Utc::now();
}
pub fn is_expired(&self) -> bool {
let timeout = chrono::Duration::hours(1);
chrono::Utc::now() - self.last_activity > timeout
}
pub fn deactivate(&mut self) {
self.active = false;
self.update_activity();
}
pub fn reset(&mut self, reset_target: Option<SessionResetTarget>) {
match reset_target {
Some(SessionResetTarget::Graph) => {
self.current_graph = None;
}
Some(SessionResetTarget::Schema) => {
self.current_schema = None;
}
Some(SessionResetTarget::TimeZone) => {
self.current_timezone = None;
}
Some(SessionResetTarget::AllParameters) => {
self.parameters.clear();
}
Some(SessionResetTarget::AllCharacteristics) => {
self.current_graph = None;
self.current_schema = None;
self.current_timezone = None;
}
Some(SessionResetTarget::Parameter(param_name)) => {
self.parameters.remove(¶m_name);
}
None => {
self.current_graph = None;
self.current_schema = None;
self.current_timezone = None;
self.parameters.clear();
}
}
self.update_activity();
}
pub fn has_role(&self, role_name: &str) -> bool {
self.roles.contains(&role_name.to_string())
}
pub fn can_access_graph(&self, graph_name: &str, action: &str) -> bool {
self.permissions.can_access_graph(graph_name, action)
}
pub fn can_access_schema(&self, schema_name: &str, action: &str) -> bool {
self.permissions.can_access_schema(schema_name, action)
}
pub fn can_perform_operation(&self, operation: &str) -> bool {
self.permissions.can_perform_operation(operation)
}
}
#[derive(Debug, Clone)]
pub enum SessionResetTarget {
Schema,
Graph,
TimeZone,
AllParameters,
AllCharacteristics,
Parameter(String),
}
#[derive(Debug, Clone)]
pub struct Session {
pub username: String,
pub storage: Arc<StorageManager>,
#[allow(dead_code)]
pub current_graph: Option<String>,
#[allow(dead_code)]
pub graphs: HashMap<String, GraphCache>,
}
impl Session {
#[allow(dead_code)] pub fn new_with_user(username: &str, storage: Arc<StorageManager>) -> Self {
Self {
username: username.to_string(),
storage,
current_graph: None,
graphs: HashMap::new(),
}
}
#[allow(dead_code)] pub fn set_current_graph(&mut self, name: &str) {
self.current_graph = Some(name.to_string());
if !self.graphs.contains_key(name) {
self.graphs.insert(name.to_string(), GraphCache::new());
}
}
#[allow(dead_code)] pub fn get_current_graph_mut(&mut self) -> Option<&mut GraphCache> {
if let Some(graph_name) = &self.current_graph {
self.graphs.get_mut(graph_name)
} else {
None
}
}
#[allow(dead_code)] pub fn get_current_graph(&self) -> Option<&GraphCache> {
if let Some(graph_name) = &self.current_graph {
self.graphs.get(graph_name)
} else {
None
}
}
#[allow(dead_code)] pub fn get_graph_mut(&mut self, name: &str) -> Option<&mut GraphCache> {
self.graphs.get_mut(name)
}
#[allow(dead_code)] pub fn get_graph(&self, name: &str) -> Option<&GraphCache> {
self.graphs.get(name)
}
#[allow(dead_code)] pub fn get_or_create_graph(&mut self, name: &str) -> &mut GraphCache {
self.graphs
.entry(name.to_string())
.or_insert_with(GraphCache::new)
}
}