From 2f1fd210652756b14f55218112a680b4e4c2691e Mon Sep 17 00:00:00 2001
From: Hugo Trentesaux <hugo@trentesaux.fr>
Date: Wed, 7 Jun 2023 14:34:30 +0200
Subject: [PATCH] move identity commands to subcommand

---
 doc/example.md             |  4 +--
 src/commands/collective.rs |  3 ++
 src/commands/identity.rs   | 71 +++++++++++++++++++++++++++++++++++++-
 src/commands/sudo.rs       |  1 +
 src/indexer.rs             | 25 ++++++--------
 src/main.rs                | 64 ++++------------------------------
 6 files changed, 94 insertions(+), 74 deletions(-)

diff --git a/doc/example.md b/doc/example.md
index 369d19b..d66db76 100644
--- a/doc/example.md
+++ b/doc/example.md
@@ -42,9 +42,9 @@ gcli --network gdev config save
 # get duniter current block
 gcli current-block
 # get balance of test1 account
-gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa get-balance
+gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa balance
 # get information about test1 identity (needs indexer)
-gcli identity --username test1
+gcli identity get --username test1
 # show address of given secret
 gcli --secret "pipe paddle ketchup filter life ice feel embody glide quantum ride usage"//2 show-address
 ```
diff --git a/src/commands/collective.rs b/src/commands/collective.rs
index d9645be..ed5fb88 100644
--- a/src/commands/collective.rs
+++ b/src/commands/collective.rs
@@ -4,6 +4,7 @@ use anyhow::Result;
 use sp_core::{sr25519::Pair, H256};
 use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner};
 
+/// list technical committee members
 pub async fn technical_committee_members(data: &Data) -> Result<()> {
 	let client = data.client();
 	let indexer = data.indexer.clone();
@@ -50,6 +51,7 @@ pub async fn technical_committee_members(data: &Data) -> Result<()> {
 	Ok(())
 }
 
+/// list technical committee proposals
 // TODO:
 // * better formatting (format pubkeys to SS58 and add usernames)
 // * display proposals indices
@@ -79,6 +81,7 @@ pub async fn technical_committee_proposals(client: &Client) -> Result<()> {
 	Ok(())
 }
 
+/// submit vote to technical committee
 pub async fn technical_committee_vote(
 	pair: Pair,
 	client: &Client,
diff --git a/src/commands/identity.rs b/src/commands/identity.rs
index efa5c43..46df5fe 100644
--- a/src/commands/identity.rs
+++ b/src/commands/identity.rs
@@ -8,6 +8,71 @@ use crate::runtime::runtime_types::sp_runtime::MultiSignature;
 use sp_core::{crypto::AccountId32, sr25519::Pair};
 use std::str::FromStr;
 
+/// define identity subcommands
+#[derive(Clone, Default, Debug, clap::Parser)]
+pub enum Subcommand {
+	/// show identity
+	#[default]
+	Show,
+	/// Fetch identity
+	Get {
+		#[clap(short = 'a', long = "address")]
+		account_id: Option<AccountId>,
+		#[clap(short = 'i', long = "identity")]
+		identity_id: Option<u32>,
+		#[clap(short = 'u', long = "username")]
+		username: Option<String>,
+	},
+	/// Create and certify an identity
+	///
+	/// Caller must be member, and the target account must exist.
+	Create { target: AccountId },
+	/// Confirm an identity
+	///
+	/// To be called by the certified not-yet-member account, to become member.
+	Confirm { name: String },
+	/// Revoke an identity immediately
+	Revoke,
+}
+
+/// handle identity commands
+pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> {
+	let mut data = data.build_client().await?.build_indexer().await?;
+	match command {
+		Subcommand::Show => {}
+		Subcommand::Get {
+			ref account_id,
+			identity_id,
+			ref username,
+		} => {
+			commands::identity::get_identity(
+				&data,
+				account_id.clone(),
+				identity_id,
+				username.clone(),
+			)
+			.await?
+		}
+		Subcommand::Create { target } => {
+			data = data.build_keypair();
+			commands::identity::create_identity(data.keypair(), data.client(), target).await?;
+		}
+		Subcommand::Confirm { name } => {
+			data = data.build_keypair();
+			commands::identity::confirm_identity(data.keypair(), data.client(), name).await?;
+		}
+		Subcommand::Revoke => {
+			data = data.build_keypair().fetch_idty_index().await?;
+			commands::identity::revoke_identity(data).await?;
+		}
+	};
+
+	Ok(())
+}
+
+// ======================
+
+/// get identity
 pub async fn get_identity(
 	data: &Data,
 	mut account_id: Option<AccountId32>,
@@ -63,11 +128,12 @@ pub async fn get_identity(
 	if let (Some(indexer), Some(account_id), None) = (&indexer, &account_id, &username) {
 		username = indexer.username_by_pubkey(&account_id.to_string()).await?;
 	}
-	println!("Username:    {}", username.unwrap_or_default());
+	println!("Username:    {}", username.unwrap_or("<no indexer>".to_string()));
 
 	Ok(())
 }
 
+/// get identity index by account id
 pub async fn get_idty_index_by_account_id(
 	client: &Client,
 	account_id: &AccountId32,
@@ -81,6 +147,7 @@ pub async fn get_idty_index_by_account_id(
 		.await?)
 }
 
+/// get identityt value by index
 pub async fn get_identity_by_index(
 	client: &Client,
 	idty_index: u32,
@@ -91,6 +158,7 @@ pub async fn get_identity_by_index(
 		.await?)
 }
 
+/// created identity
 pub async fn create_identity(
 	pair: Pair,
 	client: &Client,
@@ -112,6 +180,7 @@ pub async fn create_identity(
 	Ok(())
 }
 
+/// confirm identity
 pub async fn confirm_identity(
 	pair: Pair,
 	client: &Client,
diff --git a/src/commands/sudo.rs b/src/commands/sudo.rs
index a0c2d9a..301ce6c 100644
--- a/src/commands/sudo.rs
+++ b/src/commands/sudo.rs
@@ -3,6 +3,7 @@ use crate::*;
 use sp_core::{crypto::AccountId32, sr25519::Pair};
 use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner};
 
+/// set sudo key
 pub async fn set_key(
 	pair: Pair,
 	client: &Client,
diff --git a/src/indexer.rs b/src/indexer.rs
index ab376b8..25473cb 100644
--- a/src/indexer.rs
+++ b/src/indexer.rs
@@ -108,32 +108,22 @@ impl Indexer {
 	}
 }
 
+/// define indexer subcommands
 #[derive(Clone, Default, Debug, clap::Parser)]
 pub enum Subcommand {
 	#[default]
-	/// Show indexer endpoint
-	ShowEndpoint,
-	/// Fetch latest indexed block
-	LatestBlock,
 	/// Check that indexer and node are on the same network (same genesis hash)
 	Check,
+	/// Fetch latest indexed block
+	LatestBlock,
 }
 
+/// handle indexer commands
 pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> {
 	// build indexer because it is needed for all subcommands
 	let mut data = data.build_indexer().await?;
 	// match subcommand
 	match command {
-		Subcommand::ShowEndpoint => {
-			println!("indexer endpoint: {}", data.indexer().gql_url);
-		}
-		Subcommand::LatestBlock => {
-			println!(
-				"latest block indexed by {} is: {}",
-				data.cfg.indexer_endpoint,
-				data.indexer().fetch_latest_block().await?
-			);
-		}
 		Subcommand::Check => {
 			data = data.build_client().await?;
 			if data.genesis_hash == data.indexer_genesis_hash {
@@ -153,6 +143,13 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 				);
 			}
 		}
+		Subcommand::LatestBlock => {
+			println!(
+				"latest block indexed by {} is: {}",
+				data.cfg.indexer_endpoint,
+				data.indexer().fetch_latest_block().await?
+			);
+		}
 	};
 
 	Ok(())
diff --git a/src/main.rs b/src/main.rs
index bb19e55..c9000b2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -157,36 +157,13 @@ impl From<anyhow::Error> for GcliError {
 
 #[derive(Clone, Debug, clap::Subcommand, Default)]
 pub enum Subcommand {
-	/// Fetch account balance TODO also oneshot account
+	/// Fetch account balance
 	#[default]
-	GetBalance,
+	Balance,
 	/// Show address corresponding to given arguments
 	ShowAddress,
-	/// Fetch identity
-	Identity {
-		#[clap(short = 'p', long = "pubkey")]
-		account_id: Option<AccountId>,
-		#[clap(short = 'i', long = "identity")]
-		identity_id: Option<u32>,
-		#[clap(short = 'u', long = "username")]
-		username: Option<String>,
-	},
-	/// Create and certify an identity
-	///
-	/// Caller must be member, and the target account must exist.
-	CreateIdentity {
-		target: AccountId,
-	},
-	/// Confirm an identity
-	///
-	/// To be called by the certified not-yet-member account, to become member.
-	ConfirmIdentity {
-		name: String,
-	},
 	/// Generate a revocation document for the provided account
 	GenRevocDoc,
-	/// Revoke an identity immediately
-	RevokeIdentity,
 	/// List upcoming expirations that require an action
 	Expire {
 		/// Show certs that expire within less than this number of blocks
@@ -255,6 +232,9 @@ pub enum Subcommand {
 	RuntimeInfo,
 	/// Check current block
 	CurrentBlock,
+	/// Indentity subcommands
+	#[clap(subcommand)]
+	Identity(commands::identity::Subcommand),
 	/// Oneshot account subcommands
 	#[clap(subcommand)]
 	Oneshot(commands::oneshot::Subcommand),
@@ -279,7 +259,7 @@ async fn main() -> Result<(), GcliError> {
 	let mut data = Data::new(args.clone());
 
 	match args.subcommand {
-		Subcommand::GetBalance => {
+		Subcommand::Balance => {
 			data = data
 				.build_address()
 				.build_client()
@@ -292,41 +272,10 @@ async fn main() -> Result<(), GcliError> {
 			data = data.build_address();
 			println!("address is: {}", data.address());
 		}
-		Subcommand::CreateIdentity { target } => {
-			data = data.build_client().await?.build_keypair();
-			commands::identity::create_identity(data.keypair(), data.client(), target).await?;
-		}
-		Subcommand::ConfirmIdentity { name } => {
-			data = data.build_client().await?.build_keypair();
-			commands::identity::confirm_identity(data.keypair(), data.client(), name).await?;
-		}
-		Subcommand::RevokeIdentity => {
-			data = data
-				.build_client()
-				.await?
-				.build_keypair()
-				.fetch_idty_index()
-				.await?;
-			commands::identity::revoke_identity(data).await?;
-		}
 		Subcommand::Expire { blocks, sessions } => {
 			data = data.build_client().await?;
 			commands::expire::monitor_expirations(&data, blocks, sessions).await?
 		}
-		Subcommand::Identity {
-			ref account_id,
-			identity_id,
-			ref username,
-		} => {
-			data = data.build_client().await?;
-			commands::identity::get_identity(
-				&data,
-				account_id.clone(),
-				identity_id,
-				username.clone(),
-			)
-			.await?
-		}
 		Subcommand::GenRevocDoc => {
 			data = data
 				.build_client()
@@ -520,6 +469,7 @@ async fn main() -> Result<(), GcliError> {
 					.unwrap()
 			);
 		}
+		Subcommand::Identity(subcommand) => commands::identity::handle_command(data, subcommand).await?,
 		Subcommand::Oneshot(subcommand) => {
 			commands::oneshot::handle_command(data, subcommand).await?
 		}
-- 
GitLab