use crate::db_context::DbContext; use crate::error::Error::{MissingBaseEnvironment, MultipleBaseEnvironments}; use crate::error::Result; use crate::models::{Environment, EnvironmentIden, EnvironmentVariable}; use crate::util::UpdateSource; use log::{info, warn}; impl<'a> DbContext<'a> { pub fn get_environment(&self, id: &str) -> Result { self.find_one(EnvironmentIden::Id, id) } pub fn get_environment_by_folder_id(&self, folder_id: &str) -> Result> { let mut environments: Vec = self.find_many(EnvironmentIden::ParentId, folder_id, None)?; // Sort so we return the most recently updated environment environments.sort_by(|a, b| b.updated_at.cmp(&a.updated_at)); Ok(environments.get(0).cloned()) } pub fn get_base_environment(&self, workspace_id: &str) -> Result { let environments = self.list_environments_ensure_base(workspace_id)?; let base_environments = environments .into_iter() .filter(|e| e.parent_model == "workspace") .collect::>(); if base_environments.len() > 1 { return Err(MultipleBaseEnvironments(workspace_id.to_string())); } Ok(base_environments.first().cloned().ok_or( // Should never happen because one should be created above if it does not exist MissingBaseEnvironment(workspace_id.to_string()), )?) } /// Lists environments and will create a base environment if one doesn't exist pub fn list_environments_ensure_base(&self, workspace_id: &str) -> Result> { let mut environments = self.list_environments_dangerous(workspace_id)?; let base_environment = environments.iter().find(|e| e.parent_model == "workspace"); if let None = base_environment { let e = self.upsert_environment( &Environment { workspace_id: workspace_id.to_string(), name: "Global Variables".to_string(), parent_model: "workspace".to_string(), ..Default::default() }, &UpdateSource::Background, )?; info!("Created base environment {} for {workspace_id}", e.id); environments.push(e); } Ok(environments) } /// List environments for a workspace. Prefer list_environments_ensure_base() fn list_environments_dangerous(&self, workspace_id: &str) -> Result> { Ok(self.find_many::(EnvironmentIden::WorkspaceId, workspace_id, None)?) } pub fn delete_environment( &self, environment: &Environment, source: &UpdateSource, ) -> Result { let deleted_environment = self.delete(environment, source)?; // Recreate the base environment if we happened to delete it self.list_environments_ensure_base(&environment.workspace_id)?; Ok(deleted_environment) } pub fn delete_environment_by_id(&self, id: &str, source: &UpdateSource) -> Result { let environment = self.get_environment(id)?; self.delete_environment(&environment, source) } pub fn duplicate_environment( &self, environment: &Environment, source: &UpdateSource, ) -> Result { let mut environment = environment.clone(); environment.id = "".to_string(); self.upsert_environment(&environment, source) } /// Find other environments with the same parent folder fn list_duplicate_folder_environments(&self, environment: &Environment) -> Vec { if environment.parent_model != "folder" { return Vec::new(); } self.list_environments_dangerous(&environment.workspace_id) .unwrap_or_default() .into_iter() .filter(|e| { e.id != environment.id && e.parent_model == "folder" && e.parent_id == environment.parent_id }) .collect() } pub fn upsert_environment( &self, environment: &Environment, source: &UpdateSource, ) -> Result { let cleaned_variables = environment .variables .iter() .filter(|v| !v.name.is_empty() || !v.value.is_empty()) .cloned() .collect::>(); // Sometimes a new environment can be created via sync/import, so we'll just delete // the others when that happens. Not the best, but it's good for now. let duplicates = self.list_duplicate_folder_environments(environment); for duplicate in duplicates { warn!( "Deleting duplicate environment {} for folder {:?}", duplicate.id, environment.parent_id ); _ = self.delete(&duplicate, source); } // Automatically update the environment name based on the folder name let mut name = environment.name.clone(); match (environment.parent_model.as_str(), environment.parent_id.as_deref()) { ("folder", Some(folder_id)) => { if let Ok(folder) = self.get_folder(folder_id) { name = format!("{} Environment", folder.name); } } _ => {} } self.upsert( &Environment { name, variables: cleaned_variables, ..environment.clone() }, source, ) } pub fn resolve_environments( &self, workspace_id: &str, folder_id: Option<&str>, active_environment_id: Option<&str>, ) -> Result> { let mut environments = Vec::new(); if let Some(folder_id) = folder_id { let folder = self.get_folder(folder_id)?; // Add current folder's environment if let Some(e) = self.get_environment_by_folder_id(folder_id)? { environments.push(e); }; // Recurse up let ancestors = self.resolve_environments( workspace_id, folder.folder_id.as_deref(), active_environment_id, )?; environments.extend(ancestors); } else { // Add active and base environments if let Some(id) = active_environment_id { if let Ok(e) = self.get_environment(&id) { // Add active sub environment environments.push(e); }; }; // Add the base environment environments.push(self.get_base_environment(workspace_id)?); } Ok(environments) } }