use crate::nodes::InMemoryNode;
use crate::orchestrator::email_address::EmailAddress;
use crate::orchestrator::project::models::{AdminInfo, OrchestratorVersionInfo};
use crate::orchestrator::project::{Project, ProjectsOrchestratorApi};
use ockam_core::async_trait;
use ockam_node::Context;
#[async_trait]
impl ProjectsOrchestratorApi for InMemoryNode {
#[instrument(skip_all, fields(project_name = project_name, space_name = space_name))]
async fn create_project(
&self,
ctx: &Context,
space_name: &str,
project_name: &str,
users: Vec<String>,
) -> miette::Result<Project> {
let space = self.cli_state.get_space_by_name(space_name).await?;
let controller = self.create_controller().await?;
let project = controller
.create_project(ctx, &space.space_id(), project_name, users)
.await?;
let project = self
.cli_state
.projects()
.import_and_store_project(project.clone())
.await?;
Ok(project)
}
#[instrument(skip_all, fields(project_id = project_id))]
async fn get_project(&self, ctx: &Context, project_id: &str) -> miette::Result<Project> {
let controller = self.create_controller().await?;
match controller.get_project(ctx, project_id).await {
Ok(project) => Ok(self
.cli_state
.projects()
.import_and_store_project(project.clone())
.await?),
Err(e) => {
warn!("could no get the project {project_id} from the controller: {e}");
Ok(self.cli_state.projects().get_project(project_id).await?)
}
}
}
#[instrument(skip_all, fields(project_name = project_name))]
async fn get_project_by_name_or_default(
&self,
ctx: &Context,
project_name: &Option<String>,
) -> miette::Result<Project> {
let project_id = self
.cli_state
.projects()
.get_project_by_name_or_default(project_name)
.await?
.project_id()
.to_string();
self.get_project(ctx, &project_id).await
}
#[instrument(skip_all, fields(project_name = project_name))]
async fn get_project_by_name(
&self,
ctx: &Context,
project_name: &str,
) -> miette::Result<Project> {
let project_id = self
.cli_state
.projects()
.get_project_by_name(project_name)
.await?
.project_id()
.to_string();
self.get_project(ctx, &project_id).await
}
#[instrument(skip_all, fields(project_id = project_id, space_id = space_id))]
async fn delete_project(
&self,
ctx: &Context,
space_id: &str,
project_id: &str,
) -> miette::Result<()> {
let controller = self.create_controller().await?;
controller.delete_project(ctx, space_id, project_id).await?;
self.cli_state.reset_project_journey(project_id).await?;
Ok(self.cli_state.projects().delete_project(project_id).await?)
}
#[instrument(skip_all, fields(project_name = project_name, space_name = space_name))]
async fn delete_project_by_name(
&self,
ctx: &Context,
space_name: &str,
project_name: &str,
) -> miette::Result<()> {
let space = self.cli_state.get_space_by_name(space_name).await?;
let project = self
.cli_state
.projects()
.get_project_by_name(project_name)
.await?;
self.delete_project(ctx, &space.space_id(), project.project_id())
.await
}
#[instrument(skip_all)]
async fn get_orchestrator_version_info(
&self,
ctx: &Context,
) -> miette::Result<OrchestratorVersionInfo> {
Ok(self
.create_controller()
.await?
.get_orchestrator_version_info(ctx)
.await?)
}
#[instrument(skip_all)]
async fn get_admin_projects(&self, ctx: &Context) -> miette::Result<Vec<Project>> {
let user = match self.cli_state.get_default_user().await {
Ok(user) => user,
Err(_) => return Ok(vec![]),
};
match self.create_controller().await?.list_projects(ctx).await {
Ok(project_models) => {
for project_model in project_models {
self.get_project(ctx, &project_model.id).await?;
}
}
Err(e) => warn!("could not get the list of projects from the controller {e:?}"),
}
Ok(self
.cli_state
.projects()
.get_projects()
.await?
.into_iter()
.filter(|p| p.is_admin(&user))
.collect::<Vec<_>>())
}
#[instrument(skip_all, fields(project_id = project.project_id()))]
async fn wait_until_project_creation_operation_is_complete(
&self,
ctx: &Context,
project: Project,
) -> miette::Result<Project> {
let project = self
.create_controller()
.await?
.wait_until_project_creation_operation_is_complete(ctx, project.model())
.await?;
let project = self
.cli_state
.projects()
.import_and_store_project(project.clone())
.await?;
Ok(project)
}
#[instrument(skip_all, fields(project_id = project.project_id()))]
async fn wait_until_project_is_ready(
&self,
ctx: &Context,
project: Project,
) -> miette::Result<Project> {
self.node_manager
.wait_until_project_is_ready(ctx, &project)
.await
}
async fn add_project_admin(
&self,
ctx: &Context,
project_id: &str,
email: &EmailAddress,
) -> miette::Result<AdminInfo> {
let controller = self.create_controller().await?;
let res = controller.add_project_admin(ctx, project_id, email).await?;
self.get_project(ctx, project_id).await?;
Ok(res)
}
async fn list_project_admins(
&self,
ctx: &Context,
project_id: &str,
) -> miette::Result<Vec<AdminInfo>> {
let controller = self.create_controller().await?;
controller.list_project_admins(ctx, project_id).await
}
async fn delete_project_admin(
&self,
ctx: &Context,
project_id: &str,
email: &EmailAddress,
) -> miette::Result<()> {
let controller = self.create_controller().await?;
controller
.delete_project_admin(ctx, project_id, email)
.await?;
self.get_project(ctx, project_id).await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::cli_state::projects::Projects;
use crate::cli_state::ProjectsSqlxDatabase;
use crate::orchestrator::project::models::ProjectModel;
use ockam::identity::{
identities, ChangeHistoryRepository, ChangeHistorySqlxDatabase, IdentitiesVerification,
};
use ockam_core::Result;
use ockam_node::database::SqlxDatabase;
use ockam_vault::SoftwareVaultForVerifyingSignatures;
use quickcheck::{Arbitrary, Gen};
use std::sync::Arc;
#[tokio::test]
async fn test_project_history() -> Result<()> {
let identities = identities().await?;
let project_identifier = identities.identities_creation().create_identity().await?;
let project_identity = identities.get_identity(&project_identifier).await?;
let authority_identifier = identities.identities_creation().create_identity().await?;
let authority_identity = identities.get_identity(&authority_identifier).await?;
let db = SqlxDatabase::in_memory("").await?;
let change_history_repository = Arc::new(ChangeHistorySqlxDatabase::new(db.clone()));
let projects = Projects::new(
Arc::new(ProjectsSqlxDatabase::new(db)),
IdentitiesVerification::new(
change_history_repository.clone(),
SoftwareVaultForVerifyingSignatures::create(),
),
);
let mut g = Gen::new(100);
let mut project_model = ProjectModel::arbitrary(&mut g);
project_model.access_route = "".to_string();
project_model.authority_access_route = None;
project_model.authority_identity = Some(authority_identity.export_as_string()?);
project_model.identity = Some(project_identifier.clone());
project_model.project_change_history = Some(project_identity.export_as_string()?);
assert!(change_history_repository
.get_change_history(&project_identifier)
.await?
.is_none());
assert!(change_history_repository
.get_change_history(&authority_identifier)
.await?
.is_none());
projects.import_and_store_project(project_model).await?;
assert_eq!(
&change_history_repository
.get_change_history(&project_identifier)
.await?
.unwrap(),
project_identity.change_history()
);
assert_eq!(
&change_history_repository
.get_change_history(&authority_identifier)
.await?
.unwrap(),
authority_identity.change_history()
);
Ok(())
}
}