Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sponsors section to website #16010

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion cspell.json
Expand Up @@ -253,6 +253,7 @@
"Raghuvir",
"raquo",
"Rasmus",
"ratelimit",
"Rattray",
"rattrayalex",
"Rauch",
Expand Down Expand Up @@ -394,6 +395,7 @@
"website/playground/codeSamples.mjs",
"website/pages/googlefe164a33bda4034b.html",
"website/static/lib/**",
"website/static/playground.js"
"website/static/playground.js",
"website/data/sponsors.json"
]
}
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -184,6 +184,7 @@
"build": "node ./scripts/build/build.js",
"build:website": "node ./scripts/build-website.js",
"gen:changelog": "node ./scripts/generate-changelog.js",
"gen:sponsors": "node ./scripts/fetch-sponsors.js > ./website/data/sponsors.json",
"debug": "node bin/prettier.js --ignore-path=.prettierignore"
},
"c8": {
Expand Down
139 changes: 139 additions & 0 deletions scripts/fetch-sponsors.js
@@ -0,0 +1,139 @@
import timers from "node:timers/promises";

const OC_API_URL = process.env.OC_API_KEY
? `https://api.opencollective.com/graphql/v2?personalToken=${process.env.OC_API_KEY}`
: "https://api.opencollective.com/graphql/v2";

const transactionsGraphqlQuery = /* GraphQL */ `
query transactions($dateFrom: DateTime, $limit: Int, $offset: Int) {
transactions(
account: { slug: "prettier" }
dateFrom: $dateFrom
limit: $limit
offset: $offset
includeIncognitoTransactions: false
) {
nodes {
amountInHostCurrency {
value
}
fromAccount {
name
slug
website
imageUrl
}
createdAt
}
}
}
`;

const pageSize = 1000;
async function fetchTransactions() {
const body = {
query: transactionsGraphqlQuery,
variables: {
limit: 1000,
offset: 0,
dateFrom: new Date(
new Date().setFullYear(new Date().getFullYear() - 1),
).toISOString(), // data from last year
},
};

const allTransactionNodes = [];

let remaining = 10;
let reset;

for (;;) {
if (remaining === 0) {
await timers.setTimeout(reset - Date.now() + 100);
}

const response = await fetch(OC_API_URL, {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
});

let result;
if (response.headers.get("content-type").includes("json")) {
const json = await response.json();
if (json.error) {
remaining = 0;
reset = Date.now() + 1000 * 60; // 1 minute
} else {
remaining = Number(response.headers.get("x-ratelimit-remaining"));
reset = response.headers.get("x-ratelimit-reset") * 1000;
}
result = json;
} else {
throw new Error(await response.text());
}

const { nodes } = result.data.transactions;
for (const node of nodes) {
allTransactionNodes.push(node);
}
body.variables.offset += pageSize;
if (nodes.length < pageSize) {
return allTransactionNodes;
}
}
}

export async function fetchSponsors() {
const sponsorsMonthlyDonations = new Map();
const transactions = await fetchTransactions();
for (const transaction of transactions) {
if (!transaction.amountInHostCurrency) {
continue;
}
const amount = transaction.amountInHostCurrency.value;
if (!amount || amount <= 0) {
continue;
}
const sponsor = sponsorsMonthlyDonations.get(transaction.fromAccount.slug);
const monthlyDonations = (amount * 100) / 12;
if (!sponsor) {
sponsorsMonthlyDonations.set(transaction.fromAccount.slug, {
slug: transaction.fromAccount.slug,
name: transaction.fromAccount.name,
website: transaction.fromAccount.website,
avatar: transaction.fromAccount.imageUrl,
monthlyDonations,
});
} else {
sponsor.monthlyDonations += monthlyDonations;
}
}
const sponsors = {
gold: [],
silver: [],
bronze: [],
backers: [],
};
const sortedSponsors = [...sponsorsMonthlyDonations].sort(
(a, b) => b[1].monthlyDonations - a[1].monthlyDonations,
);
for (const [, sponsor] of sortedSponsors) {
sponsor.monthlyDonations = Math.round(sponsor.monthlyDonations);
if (sponsor.monthlyDonations >= 50000) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (sponsor.monthlyDonations >= 50000) {
if (sponsor.monthlyDonations >= 60000) { // 500 × 12

sponsors.gold.push(sponsor);
} else if (sponsor.monthlyDonations >= 30000) {
sponsors.silver.push(sponsor);
} else if (sponsor.monthlyDonations >= 10000) {
sponsors.bronze.push(sponsor);
} else {
sponsors.backers.push(sponsor);
}
}
return sponsors;
}

const sponsors = await fetchSponsors();
console.log(JSON.stringify(sponsors, null, 2));