diff --git a/api/index.js b/api/index.js index 123a03d6..51091fea 100644 --- a/api/index.js +++ b/api/index.js @@ -13,7 +13,8 @@ import { isLocaleAvailable } from "../src/translations.js"; export default async (req, res) => { const { username, - repo, + repos, + orgs, hide, hide_title, hide_border, @@ -68,6 +69,8 @@ export default async (req, res) => { try { const showStats = parseArray(show); + const repositories=parseArray(repos); + const organizations=parseArray(orgs); const stats = await fetchStats( username, parseBoolean(include_all_commits), @@ -76,7 +79,8 @@ export default async (req, res) => { showStats.includes("prs_merged_percentage"), showStats.includes("discussions_started"), showStats.includes("discussions_answered"), - repo, + repositories, + organizations, showStats.includes("prs_authored"), showStats.includes("prs_commented"), showStats.includes("prs_reviewed"), @@ -127,7 +131,8 @@ export default async (req, res) => { show: showStats, }, username, - repo, + repositories, + organizations, ), ); } catch (err) { diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index a9b4ca7b..420157a0 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -8,7 +8,7 @@ import { flexLayout, getCardColors, kFormatter, - measureText, + measureText, buildSearchFilter, } from "../common/utils.js"; import { statCardLocales } from "../translations.js"; @@ -207,7 +207,7 @@ const getStyles = ({ * @param {Partial} options The card options. * @returns {string} The stats card SVG object. */ -const renderStatsCard = (stats, options = {}, username, repo) => { +const renderStatsCard = (stats, options = {}, username, repos=[], orgs=[]) => { const { name, totalStars, @@ -351,7 +351,7 @@ const renderStatsCard = (stats, options = {}, username, repo) => { }; } - let repoFilter = repo ? "repo%3A" + encodeURIComponent(repo) + "+" : ""; + let repoFilter = buildSearchFilter(repos, orgs); if (show.includes("prs_authored")) { STATS.prs_authored = { icon: icons.prs, diff --git a/src/common/utils.js b/src/common/utils.js index b780657c..6a91ab00 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -217,6 +217,16 @@ const fallbackColor = (color, fallbackColor) => { ); }; +const buildSearchFilter = (repos=[], orgs=[])=>{ + let repoFilter = Array.isArray(repos) && repos.length > 0 + ? repos.map((r) => `repo%3A${encodeURIComponent(r)}`).join("+") + "+" + : ""; + let orgFilter = Array.isArray(orgs) && orgs.length > 0 + ? orgs.map((o) => `org%3A${encodeURIComponent(org)}`).join("+") + "+" + : ""; + return repoFilter + orgFilter; +} + /** * @typedef {import('axios').AxiosRequestConfig['data']} AxiosRequestConfigData Axios request data. * @typedef {import('axios').AxiosRequestConfig['headers']} AxiosRequestConfigHeaders Axios request headers. @@ -612,6 +622,7 @@ export { clampValue, isValidGradient, fallbackColor, + buildSearchFilter, request, flexLayout, getCardColors, diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 62cae1ce..a97698e8 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -5,6 +5,7 @@ import githubUsernameRegex from "github-username-regex"; import { calculateRank } from "../calculateRank.js"; import { retryer } from "../common/retryer.js"; import { + buildSearchFilter, CustomError, logger, MissingParamError, @@ -167,7 +168,7 @@ const statsFetcher = async ({ * @description Done like this because the GitHub API does not provide a way to fetch all the commits. See * #92#issuecomment-661026467 and #211 for more information. */ -const totalItemsFetcher = async (username, repo, type, filter) => { +const totalItemsFetcher = async (username, repos, orgs, type, filter) => { if (!githubUsernameRegex.test(username)) { logger.log("Invalid username provided."); throw new Error("Invalid username provided."); @@ -181,8 +182,8 @@ const totalItemsFetcher = async (username, repo, type, filter) => { `https://api.github.com/search/` + type + `?per_page=1&q=` + - filter + - (variables.repo ? `+repo:${variables.repo}` : ``), + buildSearchFilter(variables.repos, variables.orgs)+ + filter, headers: { "Content-Type": "application/json", Accept: "application/vnd.github.cloak-preview", @@ -193,7 +194,7 @@ const totalItemsFetcher = async (username, repo, type, filter) => { let res; try { - res = await retryer(fetchTotalItems, { login: username, repo }); + res = await retryer(fetchTotalItems, { login: username, repos, orgs }); } catch (err) { logger.log(err); throw new Error(err); @@ -231,7 +232,8 @@ const fetchStats = async ( include_merged_pull_requests = false, include_discussions = false, include_discussions_answers = false, - repo = null, + repos=[], + orgs=[], include_prs_authored = false, include_prs_commented = false, include_prs_reviewed = false, @@ -298,7 +300,8 @@ const fetchStats = async ( if (include_all_commits) { stats.totalCommits = await totalItemsFetcher( username, - repo, + repos, + orgs, "commits", `author:${username}`, ); @@ -308,7 +311,8 @@ const fetchStats = async ( if (include_prs_authored) { stats.totalPRsAuthored = await totalItemsFetcher( username, - repo, + repos, + orgs, "issues", `author:${username}+type:pr`, ); @@ -316,7 +320,8 @@ const fetchStats = async ( if (include_prs_commented) { stats.totalPRsCommented = await totalItemsFetcher( username, - repo, + repos, + orgs, "issues", `commenter:${username}+-author:${username}+type:pr`, ); @@ -324,7 +329,8 @@ const fetchStats = async ( if (include_prs_reviewed) { stats.totalPRsReviewed = await totalItemsFetcher( username, - repo, + repos, + orgs, "issues", `reviewed-by:${username}+-author:${username}+type:pr`, ); @@ -332,7 +338,8 @@ const fetchStats = async ( if (include_issues_authored) { stats.totalIssuesAuthored = await totalItemsFetcher( username, - repo, + repos, + orgs, "issues", `author:${username}+type:issue`, ); @@ -340,7 +347,8 @@ const fetchStats = async ( if (include_issues_commented) { stats.totalIssuesCommented = await totalItemsFetcher( username, - repo, + repos, + orgs, "issues", `commenter:${username}+-author:${username}+type:issue`, );