From fbf91eab28b5b9a91aa6983a41b4b170632cca9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Tue, 18 Apr 2023 22:18:03 +0200 Subject: [PATCH] resolve descriptions for proposals --- components/governance/Vote/ProposalCard.tsx | 17 ++++++- utils/governance/tools.ts | 49 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/components/governance/Vote/ProposalCard.tsx b/components/governance/Vote/ProposalCard.tsx index da1300ba..69b30adb 100644 --- a/components/governance/Vote/ProposalCard.tsx +++ b/components/governance/Vote/ProposalCard.tsx @@ -28,6 +28,7 @@ import { PublicKey } from '@solana/web3.js' import { notify } from 'utils/notifications' import Loading from '@components/shared/Loading' import { useTranslation } from 'next-i18next' +import { resolveProposalDescription } from 'utils/governance/tools' enum PROCESSED_VOTE_TYPE { APPROVE, @@ -60,10 +61,12 @@ const ProposalCard = ({ null ) const [isVoteCast, setIsVoteCast] = useState(false) + const [description, setDescription] = useState('') const governance = governances && governances[proposal.account.governance.toBase58()] const canVote = voter.voteWeight.cmp(new BN(1)) !== -1 + const descriptionLink = proposal.account.descriptionLink //Approve 0, deny 1 const vote = async (voteType: VoteKind) => { @@ -159,6 +162,18 @@ const ProposalCard = ({ } }, [proposal.pubkey.toBase58(), voter.tokenOwnerRecord?.pubkey.toBase58()]) + useEffect(() => { + const handleResolveDescription = async () => { + const description = await resolveProposalDescription(descriptionLink!) + setDescription(description) + } + if (descriptionLink) { + handleResolveDescription() + } else { + setDescription('') + } + }, [descriptionLink]) + return governance ? (
-

{proposal.account.descriptionLink}

+

{description}

{ return null } } + +const urlRegex = + // eslint-disable-next-line + /(https:\/\/)(gist\.github.com\/)([\w\/]{1,39}\/)([\w]{1,32})/ + +export async function fetchGistFile(gistUrl: string) { + const controller = new AbortController() + const pieces = gistUrl.match(urlRegex) + if (pieces) { + const justIdWithoutUser = pieces[4] + if (justIdWithoutUser) { + const apiUrl = 'https://api.github.com/gists/' + justIdWithoutUser + const apiResponse = await fetch(apiUrl, { + signal: controller.signal, + }) + const jsonContent = await apiResponse.json() + if (apiResponse.status === 200) { + const nextUrlFileName = Object.keys(jsonContent['files'])[0] + const nextUrl = jsonContent['files'][nextUrlFileName]['raw_url'] + if (nextUrl.startsWith('https://gist.githubusercontent.com/')) { + const fileResponse = await fetch(nextUrl, { + signal: controller.signal, + }) + const body = await fileResponse.json() + //console.log('fetchGistFile file', gistUrl, fileResponse) + return body + } + return undefined + } else { + console.warn('could not fetchGistFile', { + gistUrl, + apiResponse: jsonContent, + }) + } + } + } + + return undefined +} + +export async function resolveProposalDescription(descriptionLink: string) { + try { + const url = new URL(descriptionLink) + const desc = (await fetchGistFile(url.toString())) ?? descriptionLink + return desc + } catch { + return descriptionLink + } +}