-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Created the method to fetch the fellows from the parachain using Polkadot-JS. This will be updated to the new library once it becomes available. The system fetches all the available fellows with a GitHub handle and caches them. When requesting a fellow, it automatically filters the one it needs and returns an array of handles. This resolves #61 Co-authored-by: Yuri Volkov <mutantcornholio@users.noreply.github.com> Co-authored-by: Maksym Hlukhovtsov <mordamax@users.noreply.github.com> Co-authored-by: Przemek Rzad <roopert7@gmail.com>
- Loading branch information
1 parent
34a473c
commit 29b16b5
Showing
24 changed files
with
813 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,7 @@ | ||
/** @type {import('ts-jest').JestConfigWithTsJest} */ | ||
module.exports = { preset: "ts-jest", testEnvironment: "node", testMatch: [__dirname + "/src/**/test/**/*.test.ts"] }; | ||
module.exports = { | ||
preset: "ts-jest", | ||
testEnvironment: "node", | ||
testTimeout: 8_000, | ||
testMatch: [__dirname + "/src/**/test/**/*.test.ts"], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
import { ApiPromise, WsProvider } from "@polkadot/api"; | ||
|
||
import { ActionLogger, TeamApi } from "../github/types"; | ||
|
||
type FellowData = { address: string; rank: number }; | ||
|
||
export class PolkadotFellows implements TeamApi { | ||
private fellowsCache: Map<string, number> = new Map<string, number>(); | ||
|
||
constructor(private readonly logger: ActionLogger) {} | ||
|
||
async fetchAllFellows(): Promise<Map<string, number>> { | ||
let api: ApiPromise; | ||
this.logger.debug("Connecting to collective parachain"); | ||
// we connect to the collective rpc node | ||
const wsProvider = new WsProvider("wss://polkadot-collectives-rpc.polkadot.io"); | ||
api = await ApiPromise.create({ provider: wsProvider }); | ||
try { | ||
// We fetch all the members | ||
const membersObj = await api.query.fellowshipCollective.members.entries(); | ||
|
||
// We iterate over the fellow data and convert them into usable values | ||
const fellows: FellowData[] = []; | ||
for (const [key, rank] of membersObj) { | ||
// @ts-ignore | ||
const [address]: [string] = key.toHuman(); | ||
fellows.push({ address, ...(rank.toHuman() as object) } as FellowData); | ||
} | ||
this.logger.debug(JSON.stringify(fellows)); | ||
|
||
// Once we obtained this information, we disconnect this api. | ||
await api.disconnect(); | ||
|
||
this.logger.debug("Connecting to relay parachain."); | ||
// We connect to the relay chain | ||
api = await ApiPromise.create({ provider: new WsProvider("wss://rpc.polkadot.io") }); | ||
|
||
// We iterate over the different members and extract their data | ||
const users: Map<string, number> = new Map<string, number>(); | ||
for (const fellow of fellows) { | ||
this.logger.debug(`Fetching identity of '${fellow.address}', rank: ${fellow.rank}`); | ||
const fellowData = (await api.query.identity.identityOf(fellow.address)).toHuman() as | ||
| Record<string, unknown> | ||
| undefined; | ||
|
||
// If the identity is null, we ignore it. | ||
if (!fellowData) { | ||
this.logger.debug("Identity is null. Skipping"); | ||
continue; | ||
} | ||
|
||
// @ts-ignore | ||
const additional = fellowData.info.additional as [{ Raw: string }, { Raw: string }][] | undefined; | ||
|
||
// If it does not have additional data (GitHub handle goes here) we ignore it | ||
if (!additional || additional.length < 1) { | ||
this.logger.debug("Additional data is null. Skipping"); | ||
continue; | ||
} | ||
|
||
for (const additionalData of additional) { | ||
const [key, value] = additionalData; | ||
// We verify that they have an additional data of the key "github" | ||
// If it has a handle defined, we push it into the array | ||
if (key?.Raw && key?.Raw === "github" && value?.Raw && value?.Raw.length > 0) { | ||
this.logger.debug(`Found handles: '${value.Raw}'`); | ||
// We add it to the array and remove the @ if they add it to the handle | ||
users.set(value.Raw.replace("@", ""), fellow.rank); | ||
} | ||
} | ||
} | ||
|
||
this.logger.info(`Found users: ${JSON.stringify(Array.from(users.entries()))}`); | ||
|
||
return users; | ||
} catch (error) { | ||
this.logger.error(error as Error); | ||
throw error; | ||
} finally { | ||
await api.disconnect(); | ||
} | ||
} | ||
|
||
async getTeamMembers(ranking: string): Promise<string[]> { | ||
const requiredRank = Number(ranking); | ||
this.logger.info(`Fetching members of rank '${requiredRank}' or higher`); | ||
|
||
if (this.fellowsCache.size < 1) { | ||
this.logger.debug("Cache not found. Fetching fellows."); | ||
this.fellowsCache = await this.fetchAllFellows(); | ||
} | ||
const users: string[] = []; | ||
for (const [user, rank] of this.fellowsCache) { | ||
if (rank >= requiredRank) { | ||
users.push(user); | ||
} | ||
} | ||
|
||
if (users.length === 0) { | ||
throw new Error(`Found no members of rank ${requiredRank} or higher. Please see debug logs`); | ||
} | ||
|
||
this.logger.info(`GitHub members of rank '${requiredRank}' or higher are: ${users.join(",")}`); | ||
|
||
return users; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* eslint-disable @typescript-eslint/unbound-method */ | ||
import { mock, mockClear, MockProxy } from "jest-mock-extended"; | ||
|
||
import { ActionLogger, TeamApi } from "../github/types"; | ||
import { PolkadotFellows } from "../polkadot/fellows"; | ||
|
||
describe("CAPI test", () => { | ||
let fellows: TeamApi; | ||
let logger: MockProxy<ActionLogger>; | ||
|
||
beforeEach(() => { | ||
logger = mock<ActionLogger>(); | ||
fellows = new PolkadotFellows(logger); | ||
}); | ||
|
||
test("Should fetch fellows", async () => { | ||
const members = await fellows.getTeamMembers("2"); | ||
expect(members.length).toBeGreaterThan(0); | ||
}); | ||
|
||
test("Should cache fellows", async () => { | ||
const members = await fellows.getTeamMembers("2"); | ||
expect(members.length).toBeGreaterThan(0); | ||
expect(logger.debug).toHaveBeenCalledWith("Connecting to collective parachain"); | ||
mockClear(logger); | ||
const members2 = await fellows.getTeamMembers("2"); | ||
expect(members2.length).toBeGreaterThan(0); | ||
expect(logger.debug).not.toHaveBeenCalledWith("Connecting to collective parachain"); | ||
}); | ||
|
||
describe("Fetch by rank", () => { | ||
beforeEach(() => { | ||
const fellowsMap = new Map<string, number>(); | ||
fellowsMap.set("user-1", 1); | ||
fellowsMap.set("user-2", 2); | ||
fellowsMap.set("user-3", 3); | ||
fellowsMap.set("user-4", 4); | ||
fellowsMap.set("user-5", 5); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(fellows as any).fellowsCache = fellowsMap; | ||
}); | ||
test("should return fellows of a give rank", async () => { | ||
const rank1 = await fellows.getTeamMembers("1"); | ||
expect(rank1).toEqual(["user-1", "user-2", "user-3", "user-4", "user-5"]); | ||
|
||
const rank2 = await fellows.getTeamMembers("2"); | ||
expect(rank2).toEqual(["user-2", "user-3", "user-4", "user-5"]); | ||
|
||
const rank3 = await fellows.getTeamMembers("3"); | ||
expect(rank3).toEqual(["user-3", "user-4", "user-5"]); | ||
|
||
const rank4 = await fellows.getTeamMembers("4"); | ||
expect(rank4).toEqual(["user-4", "user-5"]); | ||
|
||
const rank5 = await fellows.getTeamMembers("5"); | ||
expect(rank5).toEqual(["user-5"]); | ||
}); | ||
|
||
test("should throw if there are no fellows available", async () => { | ||
await expect(fellows.getTeamMembers("6")).rejects.toThrowError( | ||
"Found no members of rank 6 or higher. Please see debug logs", | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.