diff --git a/src/commands/vault.rs b/src/commands/vault.rs index fe0583292692fc65c71f87297a39648de5542a77..a172155779390e83ff2819c1c5ba5b7de06e5cad 100644 --- a/src/commands/vault.rs +++ b/src/commands/vault.rs @@ -94,6 +94,17 @@ pub enum ListChoice { Base, } +#[derive(Debug, clap::Args, Clone)] +#[group(required = true, multiple = false)] +pub struct AddressOrVaultNameGroup { + /// SS58 Address + #[clap(short)] + address: Option<AccountId>, + /// Name of an SS58 Address in the vault + #[clap(short = 'v')] + name: Option<String>, +} + pub struct VaultDataToImport { secret_format: SecretFormat, secret_suri: String, @@ -640,68 +651,30 @@ pub fn compute_vault_accounts_row(account_tree_node: &Rc<RefCell<AccountTreeNode ] } -pub async fn retrieve_address_string<C, T: AddressOrVaultName>( +pub async fn retrieve_vault_account_for_name<C>( db: &C, - address_or_vault_name: T, -) -> Result<String, GcliError> + name_input: &String, +) -> Result<vault_account::Model, GcliError> where C: ConnectionTrait, { - if let Some(address) = address_or_vault_name.address() { - return Ok(address.to_string()); - } - - let account = retrieve_vault_account(db, address_or_vault_name).await?; + let account_tree_node = retrieve_account_tree_node_for_name(db, name_input).await?; - Ok(account.address.to_string()) + //Need this extra step to avoid borrowing issues + let account = account_tree_node.borrow().account.clone(); + Ok(account) } -pub async fn retrieve_account_tree_node<C, T: AddressOrVaultName>( +pub async fn retrieve_account_tree_node<C>( db: &C, - address_or_vault_name: T, + address_or_vault_name: AddressOrVaultNameGroup, ) -> Result<Rc<RefCell<AccountTreeNode>>, GcliError> where C: ConnectionTrait, { - let account_tree_node = if let Some(name_input) = address_or_vault_name.name() { - let (name, derivation_path_opt) = - parse_prefix_and_derivation_path_from_string_for_vault_name(name_input.to_string())?; - - let account_for_name = vault_account::find_by_name(db, &name).await?; - - let account_for_name = account_for_name.ok_or(GcliError::Input(format!( - "No account found with name:'{name}'" - )))?; - - let base_account_tree_node = - vault_account::fetch_base_account_tree_node_hierarchy_unwrapped( - db, - &account_for_name.address.to_string(), - ) - .await?; - - let account_tree_node_for_name = vault_account::get_account_tree_node_for_address( - &base_account_tree_node, - &account_for_name.address.to_string(), - ); - - match derivation_path_opt { - None => Rc::clone(&account_tree_node_for_name), - Some(path) => { - let account_tree_node_for_name_input = - vault_account::compute_name_map_for_account_tree_node( - &account_tree_node_for_name, - )? - .get(name_input) - .cloned() - .ok_or(GcliError::Input(format!( - "No account found with name:'{name}' and path:'{path}'" - )))?; - - Rc::clone(&account_tree_node_for_name_input) - } - } - } else if let Some(address) = address_or_vault_name.address() { + let account_tree_node = if let Some(name_input) = &address_or_vault_name.name { + retrieve_account_tree_node_for_name(db, name_input).await? + } else if let Some(address) = &address_or_vault_name.address { let base_account_tree_node = vault_account::fetch_base_account_tree_node_hierarchy_unwrapped( db, @@ -722,9 +695,52 @@ where Ok(account_tree_node) } -pub async fn retrieve_vault_account<C, T: AddressOrVaultName>( +pub async fn retrieve_account_tree_node_for_name<C>( + db: &C, + name_input: &String, +) -> Result<Rc<RefCell<AccountTreeNode>>, GcliError> +where + C: ConnectionTrait, +{ + let (name, derivation_path_opt) = + parse_prefix_and_derivation_path_from_string_for_vault_name(name_input.to_string())?; + + let account_for_name = vault_account::find_by_name(db, &name).await?; + + let account_for_name = account_for_name.ok_or(GcliError::Input(format!( + "No account found with name:'{name}'" + )))?; + + let base_account_tree_node = vault_account::fetch_base_account_tree_node_hierarchy_unwrapped( + db, + &account_for_name.address.to_string(), + ) + .await?; + + let account_tree_node_for_name = vault_account::get_account_tree_node_for_address( + &base_account_tree_node, + &account_for_name.address.to_string(), + ); + + Ok(match derivation_path_opt { + None => Rc::clone(&account_tree_node_for_name), + Some(path) => { + let account_tree_node_for_name_input = + vault_account::compute_name_map_for_account_tree_node(&account_tree_node_for_name)? + .get(name_input) + .cloned() + .ok_or(GcliError::Input(format!( + "No account found with name:'{name}' and path:'{path}'" + )))?; + + Rc::clone(&account_tree_node_for_name_input) + } + }) +} + +pub async fn retrieve_vault_account<C>( db: &C, - address_or_vault_name: T, + address_or_vault_name: AddressOrVaultNameGroup, ) -> Result<vault_account::Model, GcliError> where C: ConnectionTrait, diff --git a/src/data.rs b/src/data.rs index 3ad00206a18a982edbb21fb24af3a5b524e115c1..bfcb7d5f34984da9e556599cb5972833c1fb6752 100644 --- a/src/data.rs +++ b/src/data.rs @@ -2,7 +2,6 @@ use crate::commands::vault; use crate::*; use indexer::Indexer; use sea_orm::DatabaseConnection; -use std::str::FromStr; // consts pub const LOCAL_DUNITER_ENDPOINT: &str = "ws://localhost:9944"; @@ -198,15 +197,20 @@ impl Data { self.cfg.address = Some(keypair.address()); self.keypair = Some(keypair); } - // address or vault name - if let Some(address_or_vault_name) = self.args.address_or_vault_name.clone() { - let address = - vault::retrieve_address_string(self.connect_db(), address_or_vault_name).await?; - - self.cfg.address = Some(AccountId::from_str(&address).expect("invalid address")); + // address + if let Some(address) = self.args.address.clone() { + self.cfg.address = Some(address.clone()); // if giving address, cancel secret self.keypair = None } + // (vault)name + if let Some(name) = self.args.name.clone() { + let account = vault::retrieve_vault_account_for_name(self.connect_db(), &name).await?; + + self.cfg.address = Some(account.address.0.clone()); + // if giving (vault)name, cancel secret + self.keypair = None + } Ok(self) } /// build a client from url diff --git a/src/main.rs b/src/main.rs index 2e40ad54e238a0f58de57a10ffd766dda5dabdae..0435feae6b13bf10a4d8173deb3b7918a9e61dda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ pub struct Args { #[clap(subcommand)] pub subcommand: Subcommand, /// Overwrite indexer endpoint - #[clap(short, long)] + #[clap(short, long, conflicts_with_all=["no_indexer","network"])] indexer: Option<String>, /// Do not use indexer #[clap(long)] @@ -53,11 +53,14 @@ pub struct Args { /// Secret key format (seed, substrate, cesium) #[clap(short = 'S', long)] secret_format: Option<SecretFormat>, - /// Address - #[clap(flatten)] - address_or_vault_name: Option<AddressOrVaultNameGroupOptional>, + /// SS58 Address + #[clap(short, conflicts_with = "name")] + address: Option<AccountId>, + /// Name of an SS58 Address in the vault + #[clap(short = 'v')] + name: Option<String>, /// Overwrite duniter websocket RPC endpoint - #[clap(short, long)] + #[clap(short, long, conflicts_with = "network")] url: Option<String>, /// Target network (local, gdev, gtest...) #[clap(short, long)] @@ -70,51 +73,6 @@ pub struct Args { output_format: OutputFormat, } -trait AddressOrVaultName { - fn address(&self) -> Option<&AccountId>; - fn name(&self) -> Option<&String>; -} - -#[derive(Debug, clap::Args, Clone)] -#[group(required = false, multiple = false)] -pub struct AddressOrVaultNameGroupOptional { - /// SS58 Address - #[clap(short)] - address: Option<AccountId>, - /// Name of an SS58 Address in the vault - #[clap(short = 'v')] - name: Option<String>, -} - -impl AddressOrVaultName for AddressOrVaultNameGroupOptional { - fn address(&self) -> Option<&AccountId> { - self.address.as_ref() - } - fn name(&self) -> Option<&String> { - self.name.as_ref() - } -} - -#[derive(Debug, clap::Args, Clone)] -#[group(required = true, multiple = false)] -pub struct AddressOrVaultNameGroup { - /// SS58 Address - #[clap(short)] - address: Option<AccountId>, - /// Name of an SS58 Address in the vault - #[clap(short = 'v')] - name: Option<String>, -} - -impl AddressOrVaultName for AddressOrVaultNameGroup { - fn address(&self) -> Option<&AccountId> { - self.address.as_ref() - } - fn name(&self) -> Option<&String> { - self.name.as_ref() - } -} - // TODO derive the fromstr implementation /// secret format #[derive(Clone, Copy, Debug, Eq, PartialEq, Default)]