import { Api, Member, ProposalDetail, Proposals } from "../types"; import { BlockNumber } from "@polkadot/types/interfaces"; import { Channel, ElectionStage } from "@joystream/types/augment"; import { Category, Thread, Post } from "@joystream/types/forum"; import { domain } from "../../config"; import { categoryById, memberHandle, memberHandleByAccount, proposalDetail } from "./getters"; const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); const query = async (test: string, cb: () => Promise): Promise => { let result = await cb(); for (let i: number = 0; i < 10; i++) { if (result[test] !== "") return result; result = await cb(); await sleep(5000); } }; export const channels = async ( api: Api, channels: number[], sendMessage: (msg: string) => void ): Promise => { const [last, current] = channels; const messages: string[] = []; for (let id: number = last + 1; id <= current; id++) { const channel: Channel = await query("title", () => api.query.contentWorkingGroup.channelById(id) ); const member: Member = { id: channel.owner, handle: "", url: "" }; member.handle = await memberHandle(api, member.id.toJSON()); member.url = `${domain}/#/members/${member.handle}`; messages.push( `Channel ${channel.title} by ${member.handle} (${member.id})` ); } sendMessage(messages.join("\r\n\r\n")); return current; }; export const councils = async ( api: Api, currentBlock: number, sendMessage: (msg: string) => void ): Promise => { let lastBlock: number = currentBlock; const round: number = await api.query.councilElection.round(); const stage: ElectionStage | null = await api.query.councilElection.stage(); let msg = ""; if (!stage) { const councilEnd: BlockNumber = await api.query.council.termEndsAt(); lastBlock = councilEnd.toNumber(); const termDuration: BlockNumber = await api.query.councilElection.newTermDuration(); const block = lastBlock - termDuration.toNumber(); msg = `Council for round ${round} has been elected at block ${block} until block ${councilEnd}.`; } else { if (stage.isAnnouncing) { lastBlock = stage.asAnnouncing.toNumber(); const announcingPeriod: BlockNumber = await api.query.councilElection.announcingPeriod(); const block = lastBlock - announcingPeriod.toNumber(); msg = `Announcing election for round ${round} at ${block}.Apply now!`; } else if (stage.isVoting) { lastBlock = stage.asVoting.toNumber(); const votingPeriod: BlockNumber = await api.query.councilElection.votingPeriod(); const block = lastBlock - votingPeriod.toNumber(); msg = `Voting stage for council election started at block ${block}. Vote now!`; } else if (stage.isRevealing) { lastBlock = stage.asRevealing.toNumber(); const revealingPeriod: BlockNumber = await api.query.councilElection.revealingPeriod(); const block = lastBlock - revealingPeriod.toNumber(); msg = `Revealing stage for council election started at block ${block}. Don't forget to reveal your vote!`; } } sendMessage(msg); return lastBlock; }; // forum export const categories = async ( api: Api, category: number[], sendMessage: (msg: string) => void ): Promise => { const messages: string[] = []; let id: number = category[0] + 1; for (id; id <= category[1]; id++) { const cat: Category = await query("title", () => categoryById(api, id)); const msg = `Category ${id}: ${cat.title}`; messages.push(msg); } sendMessage(messages.join("\r\n\r\n")); return category[1]; }; export const posts = async ( api: Api, posts: number[], sendMessage: (msg: string) => void ): Promise => { const [last, current] = posts; const messages: string[] = []; let id: number = last + 1; for (id; id <= current; id++) { const post: Post = await query("current_text", () => api.query.forum.postById(id) ); const replyId: number = post.nr_in_thread.toNumber(); const message: string = post.current_text; const excerpt: string = message.substring(0, 100); const threadId: number = post.thread_id.toNumber(); const thread: Thread = await query("title", () => api.query.forum.threadById(threadId) ); const threadTitle: string = thread.title; const category: Category = await query("title", () => categoryById(api, thread.category_id.toNumber()) ); const handle = await memberHandleByAccount(api, post.author_id.toJSON()); const msg = `${handle} posted ${threadTitle} in ${category.title}:\n\r${excerpt} more`; messages.push(msg); } sendMessage(messages.join("\r\n\r\n")); return current; }; export const threads = async ( api: Api, threads: number[], sendMessage: (msg: string) => void ): Promise => { const [last, current] = threads; const messages: string[] = []; let id: number = last + 1; for (id; id <= current; id++) { const thread: Thread = await query("title", () => api.query.forum.threadById(id) ); const { title, author_id } = thread; const handle: string = await memberHandleByAccount(api, author_id.toJSON()); const category: Category = await query("title", () => categoryById(api, thread.category_id.toNumber()) ); const msg = `Thread ${id}: "${title}" by ${handle} in category "${category.title}" `; messages.push(msg); } sendMessage(messages.join("\r\n\r\n")); return id; }; // proposals const processActive = async ( id: number, details: ProposalDetail, sendMessage: (s: string) => void ): Promise => { const { createdAt, finalizedAt, message, parameters, result } = details; let msg = `Proposal ${id} created at block ${createdAt}.\r\n${message}`; if (details.stage === "Finalized") { let label: string = result; if (result === "Approved") { const executed = parameters.gracePeriod.toNumber() > 0 ? false : true; label = executed ? "Finalized" : "Executed"; } msg = `Proposal ${id} ${label} at block ${finalizedAt}.\r\n${message}`; sendMessage(msg); return true; } else return processPending(id, details, sendMessage); }; const processPending = async ( id: number, details: ProposalDetail, sendMessage: (s: string) => void ): Promise => { const { createdAt, message, parameters, stage } = details; if (stage === "Finalized") return processActive(id, details, sendMessage); const votingEndsAt = createdAt + parameters.votingPeriod.toNumber(); const msg = `Proposal ${id} created at block ${createdAt}.\r\n${message}\r\nYou can vote until block ${votingEndsAt}.`; sendMessage(msg); return true; }; export const proposals = async ( api: Api, prop: Proposals, sendMessage: (msg: string) => void ): Promise => { let { current, last, active, pending } = prop; for (let id: number = last++; id <= current; id++) active.push(id); for (const id of active) if (processActive(id, await proposalDetail(api, id), sendMessage)) active = active.filter((e: number) => e !== id); for (const id of pending) if (processPending(id, await proposalDetail(api, id), sendMessage)) pending = pending.filter((e: number) => e !== id); return { current, last: current, active, pending }; }; export const formatProposalMessage = (data: string[]): string => { const [id, title, type, stage, result, handle] = data; return `Type: ${type}\r\nProposer: ${handle}\r\nTitle: ${title}\r\nStage: ${stage}\r\nResult: ${result}`; };