const axios = require("axios"); const { renderError, kFormatter } = require("../utils"); require("dotenv").config(); async function fetchStats(username) { if (!username) throw Error("Invalid username"); const res = await axios({ url: "https://api.github.com/graphql", method: "post", headers: { Authorization: `bearer ${process.env.GITHUB_TOKEN}`, }, data: { query: ` query userInfo($login: String!) { user(login: $login) { name repositoriesContributedTo(first: 100, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { totalCount } contributionsCollection { totalCommitContributions } pullRequests(first: 100) { totalCount } issues(first: 100) { totalCount } repositories(first: 100) { nodes { stargazers { totalCount } } } } } `, variables: { login: username, }, }, }); const stats = { name: "", totalPRs: 0, totalCommits: 0, totalIssues: 0, totalStars: 0, contributedTo: 0, }; if (res.data.errors) { console.log(res.data.errors); throw Error("Could not fetch user"); } const user = res.data.data.user; stats.name = user.name; stats.totalIssues = user.issues.totalCount; stats.totalCommits = user.contributionsCollection.totalCommitContributions; stats.totalPRs = user.pullRequests.totalCount; stats.contributedTo = user.repositoriesContributedTo.totalCount; stats.totalStars = user.repositories.nodes.reduce((prev, curr) => { return prev + curr.stargazers.totalCount; }, 0); return stats; } const createTextNode = (icon, label, value, lheight) => { const classname = icon === "★" && "star-icon"; return ` ${icon} ${label}: ${kFormatter(value)} `; }; const renderSVG = (stats, options) => { const { name, totalStars, totalCommits, totalIssues, totalPRs, contributedTo, } = stats; const { hide, show_icons, hide_border, line_height } = options || {}; const lheight = line_height || 25; const STAT_MAP = { stars: createTextNode("★", "Total Stars", totalStars, lheight), commits: createTextNode("🕗", "Total Commits", totalCommits, lheight), prs: createTextNode("🔀", "Total PRs", totalPRs, lheight), issues: createTextNode("ⓘ", "Total Issues", totalIssues, lheight), contribs: createTextNode("📕", "Contributed to", contributedTo, lheight), }; const statItems = Object.keys(STAT_MAP) .filter((key) => !hide.includes(key)) .map((key) => STAT_MAP[key]); const height = 45 + (statItems.length + 1) * lheight; return ` ${ !hide_border && `` } ${name}'s GitHub Stats ${statItems} `; }; module.exports = async (req, res) => { const username = req.query.username; const hide = req.query.hide; const hide_border = req.query.hide_border; const show_icons = req.query.show_icons; const line_height = req.query.line_height; let stats; res.setHeader("Content-Type", "image/svg+xml"); try { stats = await fetchStats(username); } catch (err) { return res.send(renderError(err.message)); } res.send( renderSVG(stats, { hide: JSON.parse(hide || "[]"), show_icons, hide_border, line_height, }) ); };