Fall back to public Gitea stats when the API token is rejected

Tokens without scopes (Gitea >= 1.19) or revoked tokens get 403 on
/api/v1/user/repos; catch that and retry anonymously via /repos/search
so the Git widget keeps showing public stats instead of an error.
This commit is contained in:
2026-09-04 17:38:13 +02:00
parent 012eee6c45
commit c15cfc51a9
+16 -5
View File
@@ -198,12 +198,23 @@ function normalizeCommit(raw, source) {
async function getGiteaStats() { async function getGiteaStats() {
try { try {
const headers = GITEA_TOKEN ? { Authorization: `token ${GITEA_TOKEN}` } : {};
let repos = []; let repos = [];
let authHeaders = {};
// Try the token-authenticated path first (includes private repos).
if (GITEA_TOKEN) { if (GITEA_TOKEN) {
repos = await fetchJson(`${GITEA_URL}/api/v1/user/repos?limit=10`, headers); try {
} else { authHeaders = { Authorization: `token ${GITEA_TOKEN}` };
const search = await fetchJson(`${GITEA_URL}/api/v1/repos/search?limit=10`, headers); repos = await fetchJson(`${GITEA_URL}/api/v1/user/repos?limit=10`, authHeaders);
} catch {
// Token missing scopes / revoked — fall back to anonymous public stats.
authHeaders = {};
repos = [];
}
}
if (repos.length === 0) {
const search = await fetchJson(`${GITEA_URL}/api/v1/repos/search?limit=10`, {});
repos = search.data || []; repos = search.data || [];
} }
repos = repos.slice(0, 8); repos = repos.slice(0, 8);
@@ -213,7 +224,7 @@ async function getGiteaStats() {
try { try {
const list = await fetchJson( const list = await fetchJson(
`${GITEA_URL}/api/v1/repos/${repo.full_name}/commits?limit=5`, `${GITEA_URL}/api/v1/repos/${repo.full_name}/commits?limit=5`,
headers authHeaders
); );
for (const c of list.slice(0, 5)) { for (const c of list.slice(0, 5)) {
commits.push(normalizeCommit({ ...c, repo: repo.full_name }, "gitea")); commits.push(normalizeCommit({ ...c, repo: repo.full_name }, "gitea"));