From 96c34e3c6ccd03679404137c58317b6b57dfbedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Wed, 13 May 2020 11:43:01 -0700 Subject: [PATCH] Enable address to alias conversion (#1784) This commit updates the alias module so that we may convert node addresses into aliases. Naturally, the node address needs to be some kind of user node address that is known to the aliasing scheme. It's a big in-elegant that this creates a "hidden" integration point for plugins, where plugins creating new user node types should add hardcoded logic into the identity plugin's alias system. However, it is a convenience and we currently use this system, so I'm just going to add this functionality for now, and think about how the alias system should work long term (or whether we should phase it out) for another discussion. This is needed for #1773. I have `toAlias` return `null` when the address doesn't correspond to a known aliasing scheme, rather than erroring. I think erroring would be too harsh, given that it's quite possible that the user has loaded third-party plugins that haven't registered aliasing schemes upstream with us. In that case, the application should make a best effort attempt to proceed without an alias (e.g. fallback to the full address), for robustness. Test plan: Unit tests included; `yarn test` passes. --- src/plugins/identity/alias.js | 30 ++++++++++++++++++++++++++++++ src/plugins/identity/alias.test.js | 22 +++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/plugins/identity/alias.js b/src/plugins/identity/alias.js index 846d6ee..f383a5f 100644 --- a/src/plugins/identity/alias.js +++ b/src/plugins/identity/alias.js @@ -3,11 +3,15 @@ import {type NodeAddressT} from "../../core/graph"; import {githubOwnerPattern} from "../github/repoId"; import {loginAddress as githubAddress} from "../github/nodes"; +import {userNodeType as githubUserType} from "../github/declaration"; import {userAddress as discourseAddress} from "../discourse/address"; +import {userNodeType as discourseUserType} from "../discourse/declaration"; +import {identityType} from "./declaration"; import { identityAddress, USERNAME_PATTERN as _VALID_IDENTITY_PATTERN, } from "./identity"; +import {NodeAddress} from "../../core/graph"; /** An Alias is a string specification of an identity within another plugin. * @@ -64,3 +68,29 @@ export function resolveAlias( throw new Error(`Unknown type for alias: ${alias}`); } } + +/** + * Attempt to convert a NodeAddressT to an Alias. + * + * If the provided node address corresponds to a known aliasing scheme, an + * alias will be returned. Otherwise, null is returned. Since it's possible + * that the node address is a valid user node address provided by a plugin that + * didn't update this alias registry, clients should endeavor to accomodate + * those addresses rather than erroring. + */ +export function toAlias(n: NodeAddressT): Alias | null { + const parts = NodeAddress.toParts(n); + const terminator = parts[parts.length - 1]; + const prefixes: Map = new Map([ + ["github", githubUserType.prefix], + ["discourse", discourseUserType.prefix], + ["sourcecred", identityType.prefix], + ]); + + for (const [prefix, nodePrefix] of prefixes.entries()) { + if (NodeAddress.hasPrefix(n, nodePrefix)) { + return `${prefix}/${terminator}`; + } + } + return null; +} diff --git a/src/plugins/identity/alias.test.js b/src/plugins/identity/alias.test.js index 8e37604..0ec2154 100644 --- a/src/plugins/identity/alias.test.js +++ b/src/plugins/identity/alias.test.js @@ -1,9 +1,10 @@ // @flow -import {resolveAlias} from "./alias"; +import {resolveAlias, toAlias} from "./alias"; import {loginAddress as githubAddress} from "../github/nodes"; import {userAddress as discourseAddress} from "../discourse/address"; import {identityAddress} from "./identity"; +import {NodeAddress} from "../../core/graph"; describe("src/plugins/identity/alias", () => { describe("resolveAlias", () => { @@ -90,4 +91,23 @@ describe("src/plugins/identity/alias", () => { }); }); }); + describe("toAlias", () => { + function checkRoundTrip(alias) { + const addr = resolveAlias(alias, "https://example.com"); + expect(toAlias(addr)).toEqual(alias); + } + it("works for a GitHub node address", () => { + checkRoundTrip("github/example"); + }); + it("works for a Discourse node address", () => { + checkRoundTrip("discourse/example"); + }); + it("works for a identity node address", () => { + checkRoundTrip("sourcecred/example"); + }); + it("returns null for an address without an aliasing scheme", () => { + const address = NodeAddress.fromParts(["sourcecred", "plugin", "foo"]); + expect(toAlias(address)).toEqual(null); + }); + }); });