Skip to content
Snippets Groups Projects
Commit 76a19ff9 authored by Hugo Trentesaux's avatar Hugo Trentesaux
Browse files

add info on idty view (clients/rust/gcli-v2s!18)

* add info on identity command

* cli schema update
parent fbf95014
Branches
Tags
1 merge request!18add info on idty view
Pipeline #35752 passed
......@@ -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)
- [ ]
- [ ]
- [ ]
......
......@@ -2,6 +2,15 @@
## Graphql schema and queries for Duniter indexer
Update the schema with:
```sh
# install graphql client cli
cargo install graphql_client_cli
# download schema from node
graphql-client introspect-schema https://subsquid.gdev.coinduf.eu/graphql --output ./res/indexer-schema.json
```
...
## Metadata
......@@ -9,6 +18,8 @@
To update the scale-encoded Duniter metadata, spawn a node and run the subxt command.
```sh
# install subxt
cargo install subxt
# spawn a node listening on localhost:9944
duniter --dev
# fetch the metadata with subxt
......
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
}
}
}
......
This diff is collapsed.
......@@ -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?),
// get idty_id
let idty =
match (identity_id, &account_id, &username) {
// idty_id
(Some(idty), None, None) => idty,
// account_id → idty_id
(Some(account_id), None, None) => {
let idty = get_idty_index_by_account_id(client, account_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?)
}
.ok_or_else(|| anyhow!("no identity for name '{username}'"))?,
_ => {
return Err(anyhow!(
"One and only one argument is needed to fetch the identity."
return Err(GcliError::Logic(
"One and only one argument is needed to fetch the identity.".to_string(),
));
}
};
let value = value.ok_or_else(|| anyhow!("no identity value"))?;
// 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(())
}
......
......@@ -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
}
......@@ -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)]
......@@ -10,37 +11,37 @@ use crate::*;
// index → identity
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "res/indexer-schema.graphql",
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.graphql",
// 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)]
#[graphql(
schema_path = "res/indexer-schema.graphql",
schema_path = "res/indexer-schema.json",
query_path = "res/indexer-queries.graphql"
)]
pub struct IdentityByPubkey;
pub struct IdentityNameByPubkey;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "res/indexer-schema.graphql",
schema_path = "res/indexer-schema.json",
query_path = "res/indexer-queries.graphql"
)]
pub struct LatestBlock;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "res/indexer-schema.graphql",
schema_path = "res/indexer-schema.json",
query_path = "res/indexer-queries.graphql"
)]
pub struct GenesisHash;
......@@ -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> {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment