Extract identity-only derive from accounts.info (#2882)

* Extract identity-only derive from accounts.info

* Add hasIdentity

* hasIdentityMulti
This commit is contained in:
Jaco Greeff
2020-11-29 15:16:54 +01:00
committed by GitHub
parent 8e852db87c
commit f6942cc0f0
5 changed files with 143 additions and 88 deletions
@@ -12,7 +12,7 @@ import { decodeAddress } from '@polkadot/util-crypto';
import { memo } from '../util';
function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIndex | string | null | undefined): Observable<AccountIdAndIndex> {
function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIndex | Uint8Array | string | null | undefined): Observable<AccountIdAndIndex> {
try {
// yes, this can fail, don't care too much, catch will catch it
const decoded = isU8a(address)
@@ -39,7 +39,7 @@ function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIn
/**
* @name idAndIndex
* @param {(Address | AccountId | AccountIndex | string | null)} address - An accounts address in various formats.
* @param {(Address | AccountId | AccountIndex | Uint8Array | string | null)} address - An accounts address in various formats.
* @description An array containing the [[AccountId]] and [[AccountIndex]] as optional values.
* @example
* <BR>
@@ -50,7 +50,7 @@ function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIn
* });
* ```
*/
export function idAndIndex (instanceId: string, api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | string | null) => Observable<AccountIdAndIndex> {
return memo(instanceId, (address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> =>
export function idAndIndex (instanceId: string, api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | Uint8Array | string | null) => Observable<AccountIdAndIndex> {
return memo(instanceId, (address?: Address | AccountId | AccountIndex | Uint8Array | string | null): Observable<AccountIdAndIndex> =>
retrieve(api, address));
}
@@ -0,0 +1,127 @@
// Copyright 2017-2020 @polkadot/api-derive authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, IdentityInfoAdditional, Registration } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DeriveAccountRegistration, DeriveHasIdentity } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Data, Option } from '@polkadot/types';
import { u8aToString } from '@polkadot/util';
import { memo } from '../util';
const UNDEF_HEX = { toHex: () => undefined };
function dataAsString (data: Data): string | undefined {
return data.isRaw
? u8aToString(data.asRaw.toU8a(true))
: data.isNone
? undefined
: data.toHex();
}
function extractOther (additional: IdentityInfoAdditional[]): Record<string, string> {
return additional.reduce((other: Record<string, string>, [_key, _value]): Record<string, string> => {
const key = dataAsString(_key);
const value = dataAsString(_value);
if (key && value) {
other[key] = value;
}
return other;
}, {});
}
function extractIdentity (identityOfOpt?: Option<Registration>, superOf?: [AccountId, Data]): DeriveAccountRegistration {
if (!identityOfOpt?.isSome) {
return { judgements: [] };
}
const { info, judgements } = identityOfOpt.unwrap();
const topDisplay = dataAsString(info.display);
return {
display: (superOf && dataAsString(superOf[1])) || topDisplay,
displayParent: superOf && topDisplay,
email: dataAsString(info.email),
image: dataAsString(info.image),
judgements,
legal: dataAsString(info.legal),
other: extractOther(info.additional),
parent: superOf && superOf[0],
pgp: info.pgpFingerprint.unwrapOr(UNDEF_HEX).toHex(),
riot: dataAsString(info.riot),
twitter: dataAsString(info.twitter),
web: dataAsString(info.web)
};
}
function getParent (api: ApiInterfaceRx, identityOfOpt: Option<Registration> | undefined, superOfOpt: Option<ITuple<[AccountId, Data]>> | undefined): Observable<[Option<Registration> | undefined, [AccountId, Data] | undefined]> {
if (identityOfOpt?.isSome) {
// this identity has something set
return of([identityOfOpt, undefined]);
} else if (superOfOpt?.isSome) {
const superOf = superOfOpt.unwrap();
// we have a super
return combineLatest([
api.query.identity.identityOf<Option<Registration>>(superOf[0]),
of(superOf)
]);
}
// nothing of value returned
return of([undefined, undefined]);
}
export function _identityBase (instanceId: string, api: ApiInterfaceRx): (accountId?: AccountId | Uint8Array | string) => Observable<[Option<Registration> | undefined, Option<ITuple<[AccountId, Data]>> | undefined]> {
return memo(instanceId, (accountId?: AccountId | Uint8Array | string): Observable<[Option<Registration> | undefined, Option<ITuple<[AccountId, Data]>> | undefined]> =>
accountId && api.query.identity?.identityOf
? api.queryMulti<[Option<Registration>, Option<ITuple<[AccountId, Data]>>]>([
[api.query.identity.identityOf, accountId],
[api.query.identity.superOf, accountId]
])
: of([undefined, undefined])
);
}
/**
* @name identity
* @description Returns identity info for an account
*/
export function identity (instanceId: string, api: ApiInterfaceRx): (accountId?: AccountId | Uint8Array | string) => Observable<DeriveAccountRegistration> {
return memo(instanceId, (accountId?: AccountId | Uint8Array | string): Observable<DeriveAccountRegistration> =>
api.derive.accounts._identityBase(accountId).pipe(
switchMap(([identityOfOpt, superOfOpt]) => getParent(api, identityOfOpt, superOfOpt)),
map(([identityOfOpt, superOf]) => extractIdentity(identityOfOpt, superOf))
)
);
}
export function hasIdentity (instanceId: string, api: ApiInterfaceRx): (accountId: AccountId | Uint8Array | string) => Observable<DeriveHasIdentity> {
return memo(instanceId, (accountId: AccountId | Uint8Array | string): Observable<DeriveHasIdentity> =>
api.derive.accounts._identityBase(accountId).pipe(
map(([identityOfOpt, superOfOpt]: [Option<Registration> | undefined, Option<ITuple<[AccountId, Data]>> | undefined]): DeriveHasIdentity => {
const parentId = superOfOpt && superOfOpt.isSome
? superOfOpt.unwrap().toString()
: null;
const hasParent = !!parentId;
const hasIdentity = hasParent || !!(identityOfOpt && identityOfOpt.isSome);
return { hasIdentity, hasParent, parentId };
})
)
);
}
export function hasIdentityMulti (instanceId: string, api: ApiInterfaceRx): (accountIds: (AccountId | Uint8Array | string)[]) => Observable<DeriveHasIdentity[]> {
return memo(instanceId, (accountIds: (AccountId | Uint8Array | string)[]): Observable<DeriveHasIdentity[]> =>
combineLatest(
accountIds.map((accountId) => api.derive.accounts.hasIdentity(accountId))
)
);
}
@@ -5,6 +5,7 @@ export * from './accountId';
export * from './flags';
export * from './idAndIndex';
export * from './idToIndex';
export * from './identity';
export * from './indexToId';
export * from './indexes';
export * from './info';
+5 -84
View File
@@ -2,27 +2,17 @@
// SPDX-License-Identifier: Apache-2.0
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, AccountIndex, Address, Balance, IdentityInfoAdditional, Registration } from '@polkadot/types/interfaces';
import { AccountId, AccountIndex, Address, Balance } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DeriveAccountInfo, DeriveAccountRegistration } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Bytes, Data, Option, u32 } from '@polkadot/types';
import { Bytes, Option, u32 } from '@polkadot/types';
import { u8aToString } from '@polkadot/util';
import { memo } from '../util';
const UNDEF_HEX = { toHex: () => undefined };
function dataAsString (data: Data): string | undefined {
return data.isRaw
? u8aToString(data.asRaw.toU8a(true))
: data.isNone
? undefined
: data.toHex();
}
function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable<string | undefined> {
return ((
accountId && api.query.nicks?.nameOf
@@ -37,86 +27,17 @@ function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable<s
);
}
function extractOther (additional: IdentityInfoAdditional[]): Record<string, string> {
return additional.reduce((other: Record<string, string>, [_key, _value]): Record<string, string> => {
const key = dataAsString(_key);
const value = dataAsString(_value);
if (key && value) {
other[key] = value;
}
return other;
}, {});
}
function extractIdentity (identityOfOpt?: Option<Registration>, superOf?: [AccountId, Data]): DeriveAccountRegistration {
if (!identityOfOpt?.isSome) {
return { judgements: [] };
}
const { info, judgements } = identityOfOpt.unwrap();
const topDisplay = dataAsString(info.display);
return {
display: (superOf && dataAsString(superOf[1])) || topDisplay,
displayParent: superOf && topDisplay,
email: dataAsString(info.email),
image: dataAsString(info.image),
judgements,
legal: dataAsString(info.legal),
other: extractOther(info.additional),
parent: superOf && superOf[0],
pgp: info.pgpFingerprint.unwrapOr(UNDEF_HEX).toHex(),
riot: dataAsString(info.riot),
twitter: dataAsString(info.twitter),
web: dataAsString(info.web)
};
}
function retrieveIdentity (api: ApiInterfaceRx, accountId?: AccountId): Observable<DeriveAccountRegistration> {
return ((
accountId && api.query.identity?.identityOf
? api.queryMulti([
[api.query.identity.identityOf, accountId],
[api.query.identity.superOf, accountId]
])
: of([undefined, undefined])
) as Observable<[Option<Registration> | undefined, Option<ITuple<[AccountId, Data]>> | undefined]>).pipe(
switchMap(([identityOfOpt, superOfOpt]): Observable<[Option<Registration> | undefined, [AccountId, Data] | undefined]> => {
if (identityOfOpt?.isSome) {
// this identity has something set
return of([identityOfOpt, undefined]);
} else if (superOfOpt?.isSome) {
const superOf = superOfOpt.unwrap();
// we have a super
return combineLatest([
api.query.identity.identityOf<Option<Registration>>(superOf[0]),
of(superOf)
]);
}
// nothing of value returned
return of([undefined, undefined]);
}),
map(([identityOfOpt, superOf]): DeriveAccountRegistration =>
extractIdentity(identityOfOpt, superOf)
)
);
}
/**
* @name info
* @description Returns aux. info with regards to an account, current that includes the accountId, accountIndex and nickname
*/
export function info (instanceId: string, api: ApiInterfaceRx): (address?: AccountIndex | AccountId | Address | string | null) => Observable<DeriveAccountInfo> {
return memo(instanceId, (address?: AccountIndex | AccountId | Address | string | null): Observable<DeriveAccountInfo> =>
export function info (instanceId: string, api: ApiInterfaceRx): (address?: AccountIndex | AccountId | Address | Uint8Array | string | null) => Observable<DeriveAccountInfo> {
return memo(instanceId, (address?: AccountIndex | AccountId | Address | Uint8Array | string | null): Observable<DeriveAccountInfo> =>
api.derive.accounts.idAndIndex(address).pipe(
switchMap(([accountId, accountIndex]): Observable<[Partial<DeriveAccountInfo>, DeriveAccountRegistration, string?]> =>
combineLatest([
of({ accountId, accountIndex }),
retrieveIdentity(api, accountId),
api.derive.accounts.identity(accountId),
retrieveNick(api, accountId)
])
),
@@ -35,3 +35,9 @@ export interface DeriveAccountInfo {
identity: DeriveAccountRegistration;
nickname?: string;
}
export interface DeriveHasIdentity {
hasIdentity: boolean;
hasParent: boolean;
parentId: string | null;
}