From 6a0a31f720d465fa21d34bfa323bbdf40a5ff280 Mon Sep 17 00:00:00 2001 From: Hugo Trentesaux <hugo@trentesaux.fr> Date: Wed, 31 Jan 2024 17:19:41 +0100 Subject: [PATCH] add info on identity command --- README.md | 7 ++-- res/indexer-queries.graphql | 29 +++++++++-------- src/commands/identity.rs | 64 ++++++++++++++++++++++--------------- src/commands/smith.rs | 19 +++-------- src/indexer.rs | 60 ++++++++++++++++++---------------- 5 files changed, 94 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index f6f9e80..e4ae8d8 100644 --- a/README.md +++ b/README.md @@ -74,13 +74,14 @@ Secret key format can be changed using `--secret-format` with the following valu - [x] migrate all xt to submit_call_and_look_event - [x] add transfer with unit (ĞD, UD...) - [x] add more runtime-info like cert count, wot and smith params... +- [x] add more info on identity view like status, number certs emitted, received +- [x] implement squid indexer to get cert list +- [ ] implement indexer tx history... - [ ] add more info like sudo key, block interval - [ ] better format runtime info block number (duration in days...) and perbill (%) - [ ] add proper tabulation for runtime info - [ ] add clap complete for autocompletion -- [ ] allow to listen to multiple events (like CertAdded and CertRenewed) -- [ ] add more info on identity view like status, number certs emitted, received -- [ ] implement squid indexer to get cert list + tx history... +- [ ] allow to listen to multiple events (like SmithCertAdded and SmithMembershipAdded) - [ ] - [ ] - [ ] diff --git a/res/indexer-queries.graphql b/res/indexer-queries.graphql index 23e58ba..5ede81e 100644 --- a/res/indexer-queries.graphql +++ b/res/indexer-queries.graphql @@ -1,30 +1,31 @@ -query IdentityByIndex($index: Int!) { +query IdentityNameByIndex($index: Int!) { identities(where: {index_eq: $index}) { - index name - account { - id - } } } -query IdentityByName($name: String!) { - identities(where: {name_eq: $name}) { - index +query IdentityInfo($index: Int!) { + identities(where: {index_eq: $index}) { name - account { + certIssued(where: {active_eq: true}) { + receiver { + name + } + } + certReceived(where: {active_eq: true}) { + issuer { + name + } + } + linkedAccount { id } } } -query IdentityByPubkey($pubkey: String!) { +query IdentityNameByPubkey($pubkey: String!) { identities(where: {account: {id_eq: $pubkey}}) { - index name - account { - id - } } } diff --git a/src/commands/identity.rs b/src/commands/identity.rs index 5755011..de00263 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -152,37 +152,35 @@ pub async fn get_identity( account_id: Option<AccountId>, identity_id: Option<IdtyId>, username: Option<String>, -) -> Result<(), anyhow::Error> { +) -> Result<(), GcliError> { let client = data.client(); let indexer = data.indexer.clone(); - // fetch reachable information using Duniter only (no indexer) - let (idty, value) = match (&account_id, identity_id, &username) { - // idty_id → account_id - (None, Some(idty), None) => (idty, get_identity_by_index(client, idty).await?), - // account_id → idty_id - (Some(account_id), None, None) => { - let idty = get_idty_index_by_account_id(client, account_id) + // get idty_id + let idty = + match (identity_id, &account_id, &username) { + // idty_id + (Some(idty), None, None) => idty, + // account_id → idty_id + (None, Some(account_id), None) => get_idty_index_by_account_id(client, account_id) .await? - .ok_or_else(|| anyhow!("no identity for this account id"))?; - (idty, get_identity_by_index(client, idty).await?) - } - // username → idty_id and account_id - (None, None, Some(username)) => { - let idty = get_idty_index_by_name(client, username) + .ok_or_else(|| anyhow!("no identity for account '{account_id}'"))?, + // username → idty_id + (None, None, Some(username)) => get_idty_index_by_name(client, username) .await? - .ok_or_else(|| anyhow!("no identity found for this username"))?; - (idty, get_identity_by_index(client, idty).await?) - } - _ => { - return Err(anyhow!( - "One and only one argument is needed to fetch the identity." - )); - } - }; - let value = value.ok_or_else(|| anyhow!("no identity value"))?; + .ok_or_else(|| anyhow!("no identity for name '{username}'"))?, + _ => { + return Err(GcliError::Logic( + "One and only one argument is needed to fetch the identity.".to_string(), + )); + } + }; + // idty_id → value + let value = get_identity_by_index(client, idty) + .await? + .ok_or_else(|| anyhow!("no identity value for index {idty}"))?; - // print result + // --- print result --- // 1. identity index println!("Identity index: {idty}",); // 2. username (indexer needed if not provided) @@ -190,7 +188,7 @@ pub async fn get_identity( indexer .username_by_index(idty) .await? - .ok_or_else(|| anyhow!("indexer does not have username for this index"))? + .ok_or_else(|| anyhow!("indexer does not have username for this index {idty}"))? } else { "<no indexer>".to_string() }); @@ -200,6 +198,20 @@ pub async fn get_identity( // 4. status println!("Status: {:?}", value.status); + // get more info + if let Some(indexer) = &indexer { + let info = indexer.identity_info(idty).await.expect("no info"); + println!( + "Certifications: issued {}, received {}", + info.cert_issued.len(), + info.cert_received.len() + ); + let a = info.linked_account.len(); + if a > 1 { + println!("Linked accounts: {a}"); + } + } + Ok(()) } diff --git a/src/commands/smith.rs b/src/commands/smith.rs index 827e77c..163ad3d 100644 --- a/src/commands/smith.rs +++ b/src/commands/smith.rs @@ -281,18 +281,9 @@ pub async fn accept_invitation(data: &Data) -> Result<(), subxt::Error> { /// invite identity to join smith pub async fn certify_smith(data: &Data, target: IdtyId) -> Result<(), subxt::Error> { - // submit_call_and_look_event::< - // runtime::smith_members::events::CertificationReceived, - // Payload<runtime::smith_members::calls::types::CertifySmith>, - // >(data, &runtime::tx().smith_members().certify_smith(target)) - // .await - let progress = submit_call(data, &runtime::tx().smith_members().certify_smith(target)).await?; - if data.args.no_wait { - return Ok(()); - } - let events = track_progress(progress).await?; - // look for the expected event - look_event::<runtime::smith_members::events::SmithCertAdded>(data, &events)?; - look_event::<runtime::smith_members::events::SmithMembershipAdded>(data, &events)?; - Ok(()) + submit_call_and_look_event::< + runtime::smith_members::events::SmithCertAdded, + Payload<runtime::smith_members::calls::types::CertifySmith>, + >(data, &runtime::tx().smith_members().certify_smith(target)) + .await } diff --git a/src/indexer.rs b/src/indexer.rs index 24723d5..6ba5ff5 100644 --- a/src/indexer.rs +++ b/src/indexer.rs @@ -2,6 +2,7 @@ use graphql_client::{reqwest::post_graphql, GraphQLQuery}; use sp_core::Bytes; use crate::*; +use identity_info::*; // type used in parameters query // #[allow(non_camel_case_types)] @@ -13,15 +14,15 @@ use crate::*; schema_path = "res/indexer-schema.json", query_path = "res/indexer-queries.graphql" )] -pub struct IdentityByIndex; +pub struct IdentityNameByIndex; -// // name → identity -// #[derive(GraphQLQuery)] -// #[graphql( -// schema_path = "res/indexer-schema.json", -// query_path = "res/indexer-queries.graphql" -// )] -// pub struct IdentityByName; +// index → identity info +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "res/indexer-schema.json", + query_path = "res/indexer-queries.graphql" +)] +pub struct IdentityInfo; // pubkey → identity #[derive(GraphQLQuery)] @@ -29,7 +30,7 @@ pub struct IdentityByIndex; schema_path = "res/indexer-schema.json", query_path = "res/indexer-queries.graphql" )] -pub struct IdentityByPubkey; +pub struct IdentityNameByPubkey; #[derive(GraphQLQuery)] #[graphql( @@ -52,45 +53,48 @@ pub struct Indexer { } impl Indexer { + /// index → name pub async fn username_by_index(&self, index: u32) -> anyhow::Result<Option<String>> { - Ok(post_graphql::<IdentityByIndex, _>( + Ok(post_graphql::<IdentityNameByIndex, _>( &self.gql_client, &self.gql_url, - identity_by_index::Variables { + identity_name_by_index::Variables { index: index.into(), }, ) .await? .data - .and_then(|data| data.identities.first().map(|idty| idty.name.clone()))) + .and_then(move |mut data| data.identities.pop().map(|idty| idty.name))) } + /// pubkey → name pub async fn username_by_pubkey(&self, pubkey: &str) -> anyhow::Result<Option<String>> { - Ok(post_graphql::<IdentityByPubkey, _>( + Ok(post_graphql::<IdentityNameByPubkey, _>( &self.gql_client, &self.gql_url, - identity_by_pubkey::Variables { + identity_name_by_pubkey::Variables { pubkey: pubkey.to_string(), }, ) .await? .data - .and_then(|data| data.identities.first().map(|idty| idty.name.clone()))) + .and_then(move |mut data| data.identities.pop().map(|idty| idty.name))) } - // // not used anymore because available with Duniter - // pub async fn pubkey_by_username(&self, username: &str) -> anyhow::Result<Option<String>> { - // Ok(post_graphql::<IdentityByName, _>( - // &self.gql_client, - // self.gql_url.clone(), - // identity_by_name::Variables { - // name: username.to_string(), - // }, - // ) - // .await? - // .data - // .and_then(|data| data.identity.into_iter().next().map(|idty| idty.pubkey))) - // } + /// index → info + pub async fn identity_info(&self, index: u32) -> Option<IdentityInfoIdentities> { + post_graphql::<IdentityInfo, _>( + &self.gql_client, + &self.gql_url, + identity_info::Variables { + index: index.into(), + }, + ) + .await + .expect("problem") + .data + .and_then(move |mut data| data.identities.pop()) + } /// fetch latest block number pub async fn fetch_latest_block(&self) -> Result<u64, anyhow::Error> { -- GitLab