Skip to content

Commit e9e73c8

Browse files
authored
feat(plugins/sponsors): fetch more than 100 sponsors/past sponsors and display organizations (lowlighter#1003) [skip ci]
1 parent 683df66 commit e9e73c8

File tree

8 files changed

+113
-32
lines changed

8 files changed

+113
-32
lines changed

source/plugins/sponsors/index.mjs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,59 @@ export default async function({login, q, imports, data, graphql, queries, accoun
99
//Load inputs
1010
const {sections, past} = await imports.metadata.plugins.sponsors.inputs({data, account, q})
1111

12-
//Query sponsors and goal
12+
//Query description and goal
1313
console.debug(`metrics/compute/${login}/plugins > sponsors > querying sponsors and goal`)
14-
const {[account]:{sponsorsListing:{fullDescription, activeGoal}, sponsorshipsAsMaintainer:{nodes, totalCount:count}}} = await graphql(queries.sponsors({login, account}))
14+
const {[account]:{sponsorsListing:{fullDescription, activeGoal}}} = await graphql(queries.sponsors.description({login, account}))
1515
const about = await imports.markdown(fullDescription, {mode:"multiline"})
1616
const goal = activeGoal ? {progress:activeGoal.percentComplete, title:activeGoal.title, description:await imports.markdown(activeGoal.description)} : null
17-
let list = nodes.map(({sponsorEntity:{login, avatarUrl}, tier}) => ({login, avatarUrl, amount:tier?.monthlyPriceInDollars ?? null, past:false}))
18-
await Promise.all(list.map(async user => user.avatar = await imports.imgb64(user.avatarUrl)))
17+
const count = {active:{total:0, user:0, organization:0}, past:{total:0, user:0, organization:0}}
18+
19+
//Query active sponsors
20+
let list = []
21+
{
22+
const fetched = []
23+
let cursor = null
24+
let pushed = 0
25+
do {
26+
console.debug(`metrics/compute/${login}/sponsors > retrieving sponsors after ${cursor}`)
27+
const {[account]:{sponsorshipsAsMaintainer:{edges, nodes}}} = await graphql(queries.sponsors.active({login, account, after:cursor ? `after: "${cursor}"` : ""}))
28+
cursor = edges?.[edges?.length - 1]?.cursor
29+
fetched.push(...nodes)
30+
pushed = nodes.length
31+
console.debug(`metrics/compute/${login}/sponsors > retrieved ${pushed} sponsors after ${cursor}`)
32+
} while ((pushed) && (cursor))
33+
list.push(...fetched.map(({sponsorEntity:{login, avatarUrl, url:organization = null}, tier}) => ({login, avatarUrl, type:organization ? "organization" : "user", amount:tier?.monthlyPriceInDollars ?? null, past:false})))
34+
await Promise.all(list.map(async user => user.avatar = await imports.imgb64(user.avatarUrl)))
35+
count.active.total = list.length
36+
count.active.user = list.filter(user => user.type === "user").length
37+
count.active.organization = list.filter(user => user.type === "organization").length
38+
}
1939

2040
//Query past sponsors
2141
if (past) {
2242
console.debug(`metrics/compute/${login}/plugins > sponsors > querying past sponsors`)
2343
const active = new Set(list.map(({login}) => login))
24-
const {[account]:{sponsorsActivities:{nodes:events}}} = await graphql(queries.sponsors.all({login, account}))
25-
const users = events.map(({sponsor:{login, avatarUrl}, sponsorsTier}) => ({login, avatarUrl, amount:sponsorsTier?.monthlyPriceInDollars ?? null, past:true}))
44+
const users = []
45+
{
46+
const fetched = []
47+
let cursor = null
48+
let pushed = 0
49+
do {
50+
console.debug(`metrics/compute/${login}/sponsors > retrieving sponsors events after ${cursor}`)
51+
const {[account]:{sponsorsActivities:{edges, nodes}}} = await graphql(queries.sponsors.all({login, account, after:cursor ? `after: "${cursor}"` : ""}))
52+
cursor = edges?.[edges?.length - 1]?.cursor
53+
fetched.push(...nodes)
54+
pushed = nodes.length
55+
console.debug(`metrics/compute/${login}/sponsors > retrieved ${pushed} sponsors events after ${cursor}`)
56+
} while ((pushed) && (cursor))
57+
users.push(...fetched.map(({sponsor:{login, avatarUrl, url:organization = null}, sponsorsTier}) => ({login, avatarUrl, type:organization ? "organization" : "user", amount:sponsorsTier?.monthlyPriceInDollars ?? null, past:true})))
58+
}
2659
for (const user of users) {
2760
if (!active.has(user.login)) {
2861
active.add(user.login)
2962
list.push({...user, avatar:await imports.imgb64(user.avatarUrl)})
63+
count.past.total++
64+
count.past[user.type]++
3065
}
3166
}
3267
}
Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
query SponsorsDefault {
1+
query SponsorsActive {
22
$account(login: "$login") {
3-
sponsorsListing {
4-
fullDescription
5-
activeGoal {
6-
percentComplete
7-
title
8-
description
3+
sponsorshipsAsMaintainer($after first: 100) {
4+
edges {
5+
cursor
96
}
10-
}
11-
sponsorshipsAsMaintainer(first: 100) {
12-
totalCount
137
nodes {
148
sponsorEntity {
159
... on User {
1610
login
1711
avatarUrl(size: 36)
1812
}
13+
... on Organization {
14+
login
15+
avatarUrl(size: 36)
16+
url
17+
}
1918
}
2019
tier {
2120
monthlyPriceInDollars
2221
}
2322
}
2423
}
2524
}
26-
}
25+
}

source/plugins/sponsors/queries/all.graphql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
query SponsorsAll {
22
$account(login: "$login") {
3-
sponsorsActivities(last: 100, period: ALL) {
3+
sponsorsActivities($after first: 100, period: ALL) {
4+
edges {
5+
cursor
6+
}
47
nodes {
58
sponsor {
69
... on User {
710
avatarUrl
811
login
912
}
13+
... on Organization {
14+
login
15+
avatarUrl(size: 36)
16+
url
17+
}
1018
}
1119
sponsorsTier {
1220
monthlyPriceInDollars
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
query SponsorsDescription {
2+
$account(login: "$login") {
3+
sponsorsListing {
4+
fullDescription
5+
activeGoal {
6+
percentComplete
7+
title
8+
description
9+
}
10+
}
11+
}
12+
}

source/templates/classic/partials/sponsors.ejs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@
3434
<% } %>
3535
<div class="goal-text">
3636
<span>
37-
<% if (plugins.sponsors.count) { %>
38-
<%= plugins.sponsors.count %> sponsor<%= plugins.sponsors.count !== 1 ? "s are" : " is" %> funding <%= user.login %>'s work
37+
<% if (plugins.sponsors.count.active.total) { %>
38+
<%= plugins.sponsors.count.active.total %> sponsor<%= plugins.sponsors.count.active.total !== 1 ? "s are" : " is" %> funding <%= user.login %>'s work
3939
<% } %>
4040
</span>
4141
<span><%= plugins.sponsors.goal.title %></span>
4242
</div>
4343
<div class="row">
44-
<% for (const user of plugins.sponsors.list) { %><img class="avatar <%= user.past ? "past" : "" %>" src="<%= user.avatar %>" width="24" height="24" alt="" /><% } %>
44+
<% for (const user of plugins.sponsors.list) { %><img class="avatar <%= user.type === "organization" ? "organization" : "" %> <%= user.past ? "past" : "" %>" src="<%= user.avatar %>" width="24" height="24" alt="" /><% } %>
4545
</div>
4646
</section>
4747
</div>

tests/mocks/api/github/graphql/sponsors.default.mjs renamed to tests/mocks/api/github/graphql/sponsors.active.mjs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
/**Mocked data */
22
export default function({ faker, query, login = faker.internet.userName() }) {
33
console.debug("metrics/compute/mocks > mocking graphql api result > sponsors/default")
4-
return ({
4+
return /after: "MOCKED_CURSOR"/m.test(query) ?
5+
({
6+
user: {
7+
sponsorshipsAsMaintainer: {
8+
edges:[],
9+
nodes:[],
10+
}
11+
}
12+
})
13+
: ({
514
user: {
6-
sponsorsListing: {
7-
fullDescription: faker.lorem.sentences(),
8-
activeGoal: {
9-
percentComplete: faker.datatype.number(100),
10-
title: faker.lorem.sentence(),
11-
description: faker.lorem.sentence(),
12-
},
13-
},
1415
sponsorshipsAsMaintainer: {
15-
totalCount: faker.datatype.number(100),
16+
edges: new Array(10).fill("MOCKED_CURSOR"),
1617
nodes: new Array(10).fill(null).map(_ => ({
1718
sponsorEntity: {
1819
login: faker.internet.userName(),

tests/mocks/api/github/graphql/sponsors.all.mjs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
/**Mocked data */
22
export default function({ faker, query, login = faker.internet.userName() }) {
33
console.debug("metrics/compute/mocks > mocking graphql api result > sponsors/all")
4-
return ({
4+
return /after: "MOCKED_CURSOR"/m.test(query) ?
5+
({
6+
user: {
7+
sponsorsActivities: {
8+
edges:[],
9+
nodes:[],
10+
}
11+
}
12+
})
13+
: ({
514
user: {
615
sponsorsActivities: {
16+
edges: new Array(10).fill("MOCKED_CURSOR"),
717
nodes: new Array(10).fill(null).map(_ => ({
818
sponsor: {
919
login: faker.internet.userName(),
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**Mocked data */
2+
export default function({ faker, query, login = faker.internet.userName() }) {
3+
console.debug("metrics/compute/mocks > mocking graphql api result > sponsors/default")
4+
return ({
5+
user: {
6+
sponsorsListing: {
7+
fullDescription: faker.lorem.sentences(),
8+
activeGoal: {
9+
percentComplete: faker.datatype.number(100),
10+
title: faker.lorem.sentence(),
11+
description: faker.lorem.sentence(),
12+
},
13+
},
14+
},
15+
})
16+
}

0 commit comments

Comments
 (0)