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.
This commit is contained in:
Dandelion Mané 2020-05-13 11:43:01 -07:00 committed by GitHub
parent f183c51159
commit 96c34e3c6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 1 deletions

View File

@ -3,11 +3,15 @@
import {type NodeAddressT} from "../../core/graph"; import {type NodeAddressT} from "../../core/graph";
import {githubOwnerPattern} from "../github/repoId"; import {githubOwnerPattern} from "../github/repoId";
import {loginAddress as githubAddress} from "../github/nodes"; import {loginAddress as githubAddress} from "../github/nodes";
import {userNodeType as githubUserType} from "../github/declaration";
import {userAddress as discourseAddress} from "../discourse/address"; import {userAddress as discourseAddress} from "../discourse/address";
import {userNodeType as discourseUserType} from "../discourse/declaration";
import {identityType} from "./declaration";
import { import {
identityAddress, identityAddress,
USERNAME_PATTERN as _VALID_IDENTITY_PATTERN, USERNAME_PATTERN as _VALID_IDENTITY_PATTERN,
} from "./identity"; } from "./identity";
import {NodeAddress} from "../../core/graph";
/** An Alias is a string specification of an identity within another plugin. /** 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}`); 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<string, NodeAddressT> = 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;
}

View File

@ -1,9 +1,10 @@
// @flow // @flow
import {resolveAlias} from "./alias"; import {resolveAlias, toAlias} from "./alias";
import {loginAddress as githubAddress} from "../github/nodes"; import {loginAddress as githubAddress} from "../github/nodes";
import {userAddress as discourseAddress} from "../discourse/address"; import {userAddress as discourseAddress} from "../discourse/address";
import {identityAddress} from "./identity"; import {identityAddress} from "./identity";
import {NodeAddress} from "../../core/graph";
describe("src/plugins/identity/alias", () => { describe("src/plugins/identity/alias", () => {
describe("resolveAlias", () => { 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);
});
});
}); });