diff --git a/source/app/mocks/api/github/graphql/achievements.default.mjs b/source/app/mocks/api/github/graphql/achievements.default.mjs
index 6b57629e..ce14033e 100644
--- a/source/app/mocks/api/github/graphql/achievements.default.mjs
+++ b/source/app/mocks/api/github/graphql/achievements.default.mjs
@@ -61,6 +61,7 @@
following:{totalCount:faker.datatype.number(10000)},
bio:faker.lorem.sentence(),
status:{message:faker.lorem.paragraph()},
+ sponsorshipsAsSponsor:{totalCount:faker.datatype.number(100)},
},
})
}
diff --git a/source/app/mocks/api/github/graphql/achievements.organizations.mjs b/source/app/mocks/api/github/graphql/achievements.organizations.mjs
new file mode 100644
index 00000000..4e8b10bc
--- /dev/null
+++ b/source/app/mocks/api/github/graphql/achievements.organizations.mjs
@@ -0,0 +1,33 @@
+/**Mocked data */
+ export default function({faker, query, login = faker.internet.userName()}) {
+ console.debug("metrics/compute/mocks > mocking graphql api result > achievements/organizations")
+ return ({
+ organization:{
+ repositories:{
+ nodes:[
+ {
+ createdAt:faker.date.recent(),
+ nameWithOwner:`${faker.internet.userName()}/${faker.lorem.slug()}`,
+ },
+ ],
+ totalCount:faker.datatype.number(100),
+ },
+ forks:{
+ nodes:[
+ {
+ createdAt:faker.date.recent(),
+ nameWithOwner:`${faker.internet.userName()}/${faker.lorem.slug()}`,
+ },
+ ],
+ totalCount:faker.datatype.number(100),
+ },
+ popular:{
+ nodes:[{stargazers:{totalCount:faker.datatype.number(50000)}}],
+ },
+ projects:{totalCount:faker.datatype.number(100)},
+ packages:{totalCount:faker.datatype.number(100)},
+ membersWithRole:{totalCount:faker.datatype.number(100)},
+ sponsorshipsAsSponsor:{totalCount:faker.datatype.number(100)},
+ },
+ })
+ }
diff --git a/source/app/web/statics/about/index.html b/source/app/web/statics/about/index.html
index 195b6dfd..d409b21a 100644
--- a/source/app/web/statics/about/index.html
+++ b/source/app/web/statics/about/index.html
@@ -37,7 +37,7 @@
- Display rankings, highlights, commits calendar, used languages and recent activity from any user account!
+ Display rankings, contributions, highlights, commits calendar, used languages and recent activity from any user account!
Share this profile using {{ url }}
@@ -66,7 +66,7 @@
-
+
-
+
Highlights
diff --git a/source/plugins/achievements/index.mjs b/source/plugins/achievements/index.mjs
index 78aa21b7..dd7a2e07 100644
--- a/source/plugins/achievements/index.mjs
+++ b/source/plugins/achievements/index.mjs
@@ -1,3 +1,6 @@
+//Imports
+ import * as compute from "./list/index.mjs"
+
//Setup
export default async function({login, q, imports, data, computed, graphql, queries, account}, {enabled = false} = {}) {
//Plugin execution
@@ -11,272 +14,8 @@
//Initialization
const list = []
- const {user} = await graphql(queries.achievements({login}))
- const scores = {followers:user.followers.totalCount, created:user.repositories.totalCount, stars:user.popular.nodes?.[0]?.stargazers?.totalCount ?? 0, forks:Math.max(0, ...data.user.repositories.nodes.map(({forkCount}) => forkCount))}
- const ranks = await graphql(queries.achievements.ranking(scores))
- const requirements = {stars:5, followers:3, forks:1, created:1}
await total({imports})
-
- //Developer
- {
- const value = user.repositories.totalCount
- const unlock = user.repositories.nodes?.shift()
- list.push({
- title:"Developer",
- text:`Published ${value} public repositor${imports.s(value, "y")}`,
- icon:"",
- ...rank(value, [1, 20, 50, 100]), value, unlock:new Date(unlock?.createdAt),
- leaderboard:leaderboard({user:ranks.created_rank.userCount, requirement:scores.created >= requirements.created, type:"users"}),
- })
- }
-
- //Forker
- {
- const value = user.forks.totalCount
- const unlock = user.forks.nodes?.shift()
- list.push({
- title:"Forker",
- text:`Forked ${value} public repositor${imports.s(value, "y")}`,
- icon:"",
- ...rank(value, [1, 5, 10, 20]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Contributor
- {
- const value = user.pullRequests.totalCount
- const unlock = user.pullRequests.nodes?.shift()
-
- list.push({
- title:"Contributor",
- text:`Opened ${value} pull request${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Manager
- {
- const value = user.projects.totalCount
- const unlock = user.projects.nodes?.shift()
-
- list.push({
- title:"Manager",
- text:`Created ${value} user project${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 2, 3, 4]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Reviewer
- {
- const value = user.contributionsCollection.pullRequestReviewContributions.totalCount
- const unlock = user.contributionsCollection.pullRequestReviewContributions.nodes?.shift()
-
- list.push({
- title:"Reviewer",
- text:`Reviewed ${value} pull request${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Packager
- {
- const value = user.packages.totalCount
- const unlock = user.packages.nodes?.shift()
-
- list.push({
- title:"Packager",
- text:`Created ${value} package${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 5, 10, 20]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Scripter
- {
- const value = user.gists.totalCount
- const unlock = user.gists.nodes?.shift()
-
- list.push({
- title:"Scripter",
- text:`Published ${value} gist${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 20, 50, 100]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Worker
- {
- const value = user.organizations.totalCount
- const unlock = user.organizations.nodes?.shift()
-
- list.push({
- title:"Worker",
- text:`Joined ${value} organization${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 2, 3, 4]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Stargazer
- {
- const value = user.starredRepositories.totalCount
- const unlock = user.starredRepositories.nodes?.shift()
-
- list.push({
- title:"Stargazer",
- text:`Starred ${value} repositor${imports.s(value, "y")}`,
- icon:"",
- ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Follower
- {
- const value = user.following.totalCount
- const unlock = user.following.nodes?.shift()
-
- list.push({
- title:"Follower",
- text:`Following ${value} user${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Influencer
- {
- const value = user.followers.totalCount
- const unlock = user.followers.nodes?.shift()
-
- list.push({
- title:"Influencer",
- text:`Followed by ${value} user${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
- leaderboard:leaderboard({user:ranks.user_rank.userCount, requirement:scores.followers >= requirements.followers, type:"users"}),
- })
- }
-
- //Maintainer
- {
- const value = user.popular.nodes?.shift()?.stargazers?.totalCount ?? 0
- const unlock = null
-
- list.push({
- title:"Maintainer",
- text:`Maintaining a repository with ${value} star${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 1000, 5000, 10000]), value, unlock:new Date(unlock?.createdAt),
- leaderboard:leaderboard({user:ranks.repo_rank.repositoryCount, requirement:scores.stars >= requirements.stars, type:"repositories"}),
- })
- }
-
- //Inspirationer
- {
- const value = Math.max(0, ...data.user.repositories.nodes.map(({forkCount}) => forkCount))
- const unlock = null
- list.push({
- title:"Inspirationer",
- text:`Maintaining a repository which has been forked ${value} time${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 100, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
- leaderboard:leaderboard({user:ranks.forks_rank.repositoryCount, requirement:scores.forks >= requirements.forks, type:"repositories"}),
- })
- }
-
- //Polyglot
- {
- const value = new Set(data.user.repositories.nodes.flatMap(repository => repository.languages.edges.map(({node:{name}}) => name))).size
- const unlock = null
-
- list.push({
- title:"Polyglot",
- text:`Using ${value} different programming language${imports.s(value)}`,
- icon:"",
- ...rank(value, [1, 4, 8, 16]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Member
- {
- const value = computed.registered.diff
- const unlock = null
-
- list.push({
- title:"Member",
- text:`Registered ${Math.floor(value)} year${imports.s(Math.floor(value))} ago`,
- icon:"",
- ...rank(value, [1, 3, 5, 10]), value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Verified
- {
- const value = !/This user hasn't uploaded any GPG keys/i.test((await imports.axios.get(`https://github.com/${login}.gpg`)).data)
- const unlock = null
-
- list.push({
- title:"Verified",
- text:"Registered a GPG key to sign commits",
- icon:"",
- rank:value ? "$" : "X", progress:value ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Explorer
- {
- const value = !/doesn’t have any starred topics yet/i.test((await imports.axios.get(`https://github.com/stars/${login}/topics`)).data)
- const unlock = null
-
- list.push({
- title:"Explorer",
- text:"Starred a topic on GitHub Explore",
- icon:"",
- rank:value ? "$" : "X", progress:value ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Automater
- {
- const value = process.env.GITHUB_ACTIONS
- const unlock = null
-
- list.push({
- title:"Automater",
- text:"Use GitHub Actions to automate profile updates",
- icon:"",
- rank:value ? "$" : "X", progress:value ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Infographile
- {
- const {repository:{viewerHasStarred:value}, viewer:{login:_login}} = await graphql(queries.achievements.metrics())
- const unlock = null
-
- list.push({
- title:"Infographile",
- text:"Fervent supporter of metrics",
- icon:"",
- rank:(value)&&(login === _login) ? "$" : "X", progress:(value)&&(login === _login) ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
- })
- }
-
- //Octonaut
- {
- const {user:{viewerIsFollowing:value}, viewer:{login:_login}} = await graphql(queries.achievements.octocat())
- const unlock = null
-
- list.push({
- title:"Octonaut",
- text:"Following octocat",
- icon:"",
- rank:(value)&&(login === _login) ? "$" : "X", progress:(value)&&(login === _login) ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
- })
- }
+ await compute[account]({list, login, data, computed, imports, graphql, queries, rank, leaderboard})
//Results
const order = {S:5, A:4, B:3, C:2, $:1, X:0}
diff --git a/source/plugins/achievements/list/index.mjs b/source/plugins/achievements/list/index.mjs
new file mode 100644
index 00000000..5fa5e266
--- /dev/null
+++ b/source/plugins/achievements/list/index.mjs
@@ -0,0 +1,3 @@
+//Exports
+ export {default as user} from "./users.mjs"
+ export {default as organization} from "./organizations.mjs"
\ No newline at end of file
diff --git a/source/plugins/achievements/list/organizations.mjs b/source/plugins/achievements/list/organizations.mjs
new file mode 100644
index 00000000..4f94e734
--- /dev/null
+++ b/source/plugins/achievements/list/organizations.mjs
@@ -0,0 +1,140 @@
+/**Achievements list for users accounts */
+ export default async function({list, login, data, computed, imports, graphql, queries, rank, leaderboard}) {
+
+ //Initialization
+ const {organization} = await graphql(queries.achievements.organizations({login}))
+ const scores = {followers:0, created:organization.repositories.totalCount, stars:organization.popular.nodes?.[0]?.stargazers?.totalCount ?? 0, forks:Math.max(0, ...data.user.repositories.nodes.map(({forkCount}) => forkCount))}
+ const ranks = await graphql(queries.achievements.ranking(scores))
+ const requirements = {stars:5, followers:3, forks:1, created:1}
+
+ //Developers
+ {
+ const value = organization.repositories.totalCount
+ const unlock = organization.repositories.nodes?.shift()
+ list.push({
+ title:"Developers",
+ text:`Published ${value} public repositor${imports.s(value, "y")}`,
+ icon:"",
+ ...rank(value, [1, 50, 100, 200]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.created_rank.userCount, requirement:scores.created >= requirements.created, type:"users"}),
+ })
+ }
+
+ //Forkers
+ {
+ const value = organization.forks.totalCount
+ const unlock = organization.forks.nodes?.shift()
+ list.push({
+ title:"Forkers",
+ text:`Forked ${value} public repositor${imports.s(value, "y")}`,
+ icon:"",
+ ...rank(value, [1, 10, 30, 50]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Managers
+ {
+ const value = organization.projects.totalCount
+ const unlock = organization.projects.nodes?.shift()
+
+ list.push({
+ title:"Managers",
+ text:`Created ${value} user project${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 2, 4, 8]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Packagers
+ {
+ const value = organization.packages.totalCount
+ const unlock = organization.packages.nodes?.shift()
+
+ list.push({
+ title:"Packagers",
+ text:`Created ${value} package${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 20, 50, 100]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Maintainers
+ {
+ const value = organization.popular.nodes?.shift()?.stargazers?.totalCount ?? 0
+ const unlock = null
+
+ list.push({
+ title:"Maintainers",
+ text:`Maintaining a repository with ${value} star${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 5000, 10000, 30000]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.repo_rank.repositoryCount, requirement:scores.stars >= requirements.stars, type:"repositories"}),
+ })
+ }
+
+ //Inspirationers
+ {
+ const value = Math.max(0, ...data.user.repositories.nodes.map(({forkCount}) => forkCount))
+ const unlock = null
+ list.push({
+ title:"Inspirationers",
+ text:`Maintaining a repository which has been forked ${value} time${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 500, 1000, 3000]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.forks_rank.repositoryCount, requirement:scores.forks >= requirements.forks, type:"repositories"}),
+ })
+ }
+
+ //Polyglots
+ {
+ const value = new Set(data.user.repositories.nodes.flatMap(repository => repository.languages.edges.map(({node:{name}}) => name))).size
+ const unlock = null
+
+ list.push({
+ title:"Polyglots",
+ text:`Using ${value} different programming language${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 8, 16, 32]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Sponsors
+ {
+ const value = organization.sponsorshipsAsSponsor.totalCount
+ const unlock = null
+
+ list.push({
+ title:"Sponsors",
+ text:`Sponsoring ${value} user${imports.s(value)} or organization${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 5, 10, 20]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Organization
+ {
+ const value = organization.membersWithRole.totalCount
+ const unlock = null
+
+ list.push({
+ title:"Organization",
+ text:`Has ${value} member${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 100, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Member
+ {
+ const value = computed.registered.diff
+ const unlock = null
+
+ list.push({
+ title:"Member",
+ text:`Registered ${Math.floor(value)} year${imports.s(Math.floor(value))} ago`,
+ icon:"",
+ ...rank(value, [1, 3, 5, 10]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ }
\ No newline at end of file
diff --git a/source/plugins/achievements/list/users.mjs b/source/plugins/achievements/list/users.mjs
new file mode 100644
index 00000000..178f8a7b
--- /dev/null
+++ b/source/plugins/achievements/list/users.mjs
@@ -0,0 +1,284 @@
+/**Achievements list for users accounts */
+ export default async function({list, login, data, computed, imports, graphql, queries, rank, leaderboard}) {
+
+ //Initialization
+ const {user} = await graphql(queries.achievements({login}))
+ const scores = {followers:user.followers.totalCount, created:user.repositories.totalCount, stars:user.popular.nodes?.[0]?.stargazers?.totalCount ?? 0, forks:Math.max(0, ...data.user.repositories.nodes.map(({forkCount}) => forkCount))}
+ const ranks = await graphql(queries.achievements.ranking(scores))
+ const requirements = {stars:5, followers:3, forks:1, created:1}
+
+ //Developer
+ {
+ const value = user.repositories.totalCount
+ const unlock = user.repositories.nodes?.shift()
+ list.push({
+ title:"Developer",
+ text:`Published ${value} public repositor${imports.s(value, "y")}`,
+ icon:"",
+ ...rank(value, [1, 20, 50, 100]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.created_rank.userCount, requirement:scores.created >= requirements.created, type:"users"}),
+ })
+ }
+
+ //Forker
+ {
+ const value = user.forks.totalCount
+ const unlock = user.forks.nodes?.shift()
+ list.push({
+ title:"Forker",
+ text:`Forked ${value} public repositor${imports.s(value, "y")}`,
+ icon:"",
+ ...rank(value, [1, 5, 10, 20]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Contributor
+ {
+ const value = user.pullRequests.totalCount
+ const unlock = user.pullRequests.nodes?.shift()
+
+ list.push({
+ title:"Contributor",
+ text:`Opened ${value} pull request${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Manager
+ {
+ const value = user.projects.totalCount
+ const unlock = user.projects.nodes?.shift()
+
+ list.push({
+ title:"Manager",
+ text:`Created ${value} user project${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 2, 3, 4]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Reviewer
+ {
+ const value = user.contributionsCollection.pullRequestReviewContributions.totalCount
+ const unlock = user.contributionsCollection.pullRequestReviewContributions.nodes?.shift()
+
+ list.push({
+ title:"Reviewer",
+ text:`Reviewed ${value} pull request${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Packager
+ {
+ const value = user.packages.totalCount
+ const unlock = user.packages.nodes?.shift()
+
+ list.push({
+ title:"Packager",
+ text:`Created ${value} package${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 5, 10, 20]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Scripter
+ {
+ const value = user.gists.totalCount
+ const unlock = user.gists.nodes?.shift()
+
+ list.push({
+ title:"Scripter",
+ text:`Published ${value} gist${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 20, 50, 100]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Worker
+ {
+ const value = user.organizations.totalCount
+ const unlock = user.organizations.nodes?.shift()
+
+ list.push({
+ title:"Worker",
+ text:`Joined ${value} organization${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 2, 4, 8]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Stargazer
+ {
+ const value = user.starredRepositories.totalCount
+ const unlock = user.starredRepositories.nodes?.shift()
+
+ list.push({
+ title:"Stargazer",
+ text:`Starred ${value} repositor${imports.s(value, "y")}`,
+ icon:"",
+ ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Follower
+ {
+ const value = user.following.totalCount
+ const unlock = user.following.nodes?.shift()
+
+ list.push({
+ title:"Follower",
+ text:`Following ${value} user${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Influencer
+ {
+ const value = user.followers.totalCount
+ const unlock = user.followers.nodes?.shift()
+
+ list.push({
+ title:"Influencer",
+ text:`Followed by ${value} user${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 200, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.user_rank.userCount, requirement:scores.followers >= requirements.followers, type:"users"}),
+ })
+ }
+
+ //Maintainer
+ {
+ const value = user.popular.nodes?.shift()?.stargazers?.totalCount ?? 0
+ const unlock = null
+
+ list.push({
+ title:"Maintainer",
+ text:`Maintaining a repository with ${value} star${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 1000, 5000, 10000]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.repo_rank.repositoryCount, requirement:scores.stars >= requirements.stars, type:"repositories"}),
+ })
+ }
+
+ //Inspirationer
+ {
+ const value = Math.max(0, ...data.user.repositories.nodes.map(({forkCount}) => forkCount))
+ const unlock = null
+ list.push({
+ title:"Inspirationer",
+ text:`Maintaining a repository which has been forked ${value} time${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 100, 500, 1000]), value, unlock:new Date(unlock?.createdAt),
+ leaderboard:leaderboard({user:ranks.forks_rank.repositoryCount, requirement:scores.forks >= requirements.forks, type:"repositories"}),
+ })
+ }
+
+ //Polyglot
+ {
+ const value = new Set(data.user.repositories.nodes.flatMap(repository => repository.languages.edges.map(({node:{name}}) => name))).size
+ const unlock = null
+
+ list.push({
+ title:"Polyglot",
+ text:`Using ${value} different programming language${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 4, 8, 16]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Member
+ {
+ const value = computed.registered.diff
+ const unlock = null
+
+ list.push({
+ title:"Member",
+ text:`Registered ${Math.floor(value)} year${imports.s(Math.floor(value))} ago`,
+ icon:"",
+ ...rank(value, [1, 3, 5, 10]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Sponsors
+ {
+ const value = user.sponsorshipsAsSponsor.totalCount
+ const unlock = null
+
+ list.push({
+ title:"Sponsor",
+ text:`Sponsoring ${value} user${imports.s(value)} or organization${imports.s(value)}`,
+ icon:"",
+ ...rank(value, [1, 3, 5, 10]), value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Verified
+ {
+ const value = !/This user hasn't uploaded any GPG keys/i.test((await imports.axios.get(`https://github.com/${login}.gpg`)).data)
+ const unlock = null
+
+ list.push({
+ title:"Verified",
+ text:"Registered a GPG key to sign commits",
+ icon:"",
+ rank:value ? "$" : "X", progress:value ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Explorer
+ {
+ const value = !/doesn’t have any starred topics yet/i.test((await imports.axios.get(`https://github.com/stars/${login}/topics`)).data)
+ const unlock = null
+
+ list.push({
+ title:"Explorer",
+ text:"Starred a topic on GitHub Explore",
+ icon:"",
+ rank:value ? "$" : "X", progress:value ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Automater
+ {
+ const value = process.env.GITHUB_ACTIONS
+ const unlock = null
+
+ list.push({
+ title:"Automater",
+ text:"Use GitHub Actions to automate profile updates",
+ icon:"",
+ rank:value ? "$" : "X", progress:value ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Infographile
+ {
+ const {repository:{viewerHasStarred:value}, viewer:{login:_login}} = await graphql(queries.achievements.metrics())
+ const unlock = null
+
+ list.push({
+ title:"Infographile",
+ text:"Fervent supporter of metrics",
+ icon:"",
+ rank:(value)&&(login === _login) ? "$" : "X", progress:(value)&&(login === _login) ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ //Octonaut
+ {
+ const {user:{viewerIsFollowing:value}, viewer:{login:_login}} = await graphql(queries.achievements.octocat())
+ const unlock = null
+
+ list.push({
+ title:"Octonaut",
+ text:"Following octocat",
+ icon:"",
+ rank:(value)&&(login === _login) ? "$" : "X", progress:(value)&&(login === _login) ? 1 : 0, value, unlock:new Date(unlock?.createdAt),
+ })
+ }
+
+ }
\ No newline at end of file
diff --git a/source/plugins/achievements/metadata.yml b/source/plugins/achievements/metadata.yml
index 64b4d7d0..40582504 100644
--- a/source/plugins/achievements/metadata.yml
+++ b/source/plugins/achievements/metadata.yml
@@ -4,6 +4,7 @@ categorie: github
index: 17
supports:
- user
+ - organization
inputs:
# Enable or disable plugin
diff --git a/source/plugins/achievements/queries/achievements.graphql b/source/plugins/achievements/queries/achievements.graphql
index 4be7f0b2..1834eb95 100644
--- a/source/plugins/achievements/queries/achievements.graphql
+++ b/source/plugins/achievements/queries/achievements.graphql
@@ -91,5 +91,8 @@ query AchievementsDefault {
status {
message
}
+ sponsorshipsAsSponsor {
+ totalCount
+ }
}
}
diff --git a/source/plugins/achievements/queries/organizations.graphql b/source/plugins/achievements/queries/organizations.graphql
new file mode 100644
index 00000000..f50cc56f
--- /dev/null
+++ b/source/plugins/achievements/queries/organizations.graphql
@@ -0,0 +1,37 @@
+query AchievementsOrganizations {
+ organization(login: "$login") {
+ repositories(first: 1, privacy: PUBLIC, affiliations: OWNER, orderBy: {field: CREATED_AT, direction: ASC}) {
+ nodes {
+ createdAt
+ nameWithOwner
+ }
+ totalCount
+ }
+ forks:repositories(first: 1, privacy: PUBLIC, isFork: true, orderBy: {field: CREATED_AT, direction: ASC}) {
+ nodes {
+ createdAt
+ nameWithOwner
+ }
+ totalCount
+ }
+ popular:repositories(first:1, orderBy: {field: STARGAZERS, direction: DESC}) {
+ nodes {
+ stargazers {
+ totalCount
+ }
+ }
+ }
+ projects(first: 1, orderBy: {field: CREATED_AT, direction: ASC}) {
+ totalCount
+ }
+ packages(first: 1, orderBy: {direction: ASC, field: CREATED_AT}) {
+ totalCount
+ }
+ membersWithRole {
+ totalCount
+ }
+ sponsorshipsAsSponsor {
+ totalCount
+ }
+ }
+}
\ No newline at end of file