今天是第二十五天我們可以寫一個 javascript 連結github程式碼網頁程式管理系統,以下是我的程式碼
首先,你需要在 GitHub Developer Settings 中建立一個 OAuth 應用程式。獲得以下資訊:
Client ID
Client Secret
http://localhost:3000/callback
用戶點擊登入按鈕時,會被重定向到 GitHub 登入頁面,授權完成後重定向回你的應用。
// 用戶點擊時重定向到 GitHub OAuth 登入頁面
function redirectToGitHubOAuth() {
    const clientId = '你的-client-id'; // 使用你在 GitHub 取得的 Client ID
    const redirectUri = 'http://localhost:3000/callback'; // 你設定的重定向 URI
    const scope = 'repo'; // 設置權限範圍,如存取所有儲存庫
    const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}`;
    window.location.href = authUrl;
}
當 GitHub 重定向回你的應用後,你需要將 code 發送到你的伺服器(或直接在前端處理,取決於應用設計),以獲得存取令牌。
// OAuth 回調處理邏輯
function handleOAuthCallback() {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get('code');
    if (code) {
        // 將 'code' 發送到伺服器換取存取令牌
        fetch('https://your-server.com/oauth/callback', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ code }),
        })
        .then(response => response.json())
        .then(data => {
            // 存儲存取令牌,後續請求中需要
            const accessToken = data.access_token;
            localStorage.setItem('github_token', accessToken);
            loadRepositories();
        });
    }
}
透過 GitHub API 和存取令牌來取得使用者的儲存庫列表。
// 使用存取令牌從 GitHub API 獲取使用者儲存庫列表
function loadRepositories() {
    const token = localStorage.getItem('github_token');
    fetch('https://api.github.com/user/repos', {
        headers: {
            Authorization: `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(repos => {
        const repoList = document.getElementById('repo-list');
        repoList.innerHTML = '';  // 清空列表
        repos.forEach(repo => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `<a href="#" onclick="loadCommits('${repo.full_name}')">${repo.name}</a>`;
            repoList.appendChild(listItem);
        });
    });
}
點選儲存庫名稱後,載入並顯示提交紀錄。
// 根據選定儲存庫的名稱載入其提交紀錄
function loadCommits(repoFullName) {
    const token = localStorage.getItem('github_token');
    fetch(`https://api.github.com/repos/${repoFullName}/commits`, {
        headers: {
            Authorization: `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(commits => {
        const commitList = document.getElementById('commit-list');
        commitList.innerHTML = '';  // 清空提交紀錄列表
        commits.forEach(commit => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `${commit.commit.author.name}: ${commit.commit.message}`;
            commitList.appendChild(listItem);
        });
    });
}
你可以讓使用者查看、建立或更新儲存庫中的 issue。
// 取得儲存庫的所有 issue
function loadIssues(repoFullName) {
    const token = localStorage.getItem('github_token');
    fetch(`https://api.github.com/repos/${repoFullName}/issues`, {
        headers: {
            Authorization: `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(issues => {
        const issueList = document.getElementById('issue-list');
        issueList.innerHTML = '';  // 清空 issue 列表
        issues.forEach(issue => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `${issue.title}: ${issue.body}`;
            issueList.appendChild(listItem);
        });
    });
}
// 建立新 issue
function createIssue(repoFullName, issueTitle, issueBody) {
    const token = localStorage.getItem('github_token');
    fetch(`https://api.github.com/repos/${repoFullName}/issues`, {
        method: 'POST',
        headers: {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            title: issueTitle,
            body: issueBody
        })
    })
    .then(response => response.json())
    .then(issue => {
        alert(`Issue created: ${issue.title}`);
        loadIssues(repoFullName);  // 更新 issue 列表
    });
}
你可以使用 Bootstrap 或其他前端框架來建立一個簡單易用的 UI:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GitHub Repo Manager</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <script defer src="app.js"></script>
</head>
<body>
    <div class="container">
        <h1>GitHub 程式碼管理系統</h1>
        <button class="btn btn-primary" onclick="redirectToGitHubOAuth()">登入 GitHub</button>
        <h2>你的儲存庫</h2>
        <ul id="repo-list"></ul>
        <h3>提交紀錄</h3>
        <ul id="commit-list"></ul>
        <h3>Issue 列表</h3>
        <ul id="issue-list"></ul>
    </div>
</body>
</html>
redirectToGitHubOAuth 函數)這段程式碼的目的是引導使用者到 GitHub OAuth 登錄頁面,請求授權來存取其 GitHub 帳戶的資料。
function redirectToGitHubOAuth() {
    const clientId = '你的-client-id'; // 使用你在 GitHub 取得的 Client ID
    const redirectUri = 'http://localhost:3000/callback'; // 你設定的重定向 URI
    const scope = 'repo'; // 設置權限範圍,如存取所有儲存庫
    const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}`;
    window.location.href = authUrl;
}
clientId:這是你在 GitHub 開發者設定中註冊的 OAuth 應用程式時,GitHub 提供的客戶端 ID。這個 ID 會識別你的應用程式。redirectUri:這是使用者授權後,GitHub 將其重定向的 URL,應該是你應用程式的某個 URL。當使用者授權後,GitHub 會將授權碼(code)發送到這個 URI。scope:表示你希望存取的 GitHub 資料範圍,例如 repo 代表儲存庫相關的資料。window.location.href:這行程式碼會將使用者導向到 GitHub OAuth 認證頁面。當使用者同意授權後,GitHub 會將使用者重定向回你的應用程式,並附帶授權碼。
handleOAuthCallback 函數)當使用者從 GitHub 重定向回你的應用程式時,這個函數會處理回調中的授權碼,並用該授權碼換取存取令牌。
function handleOAuthCallback() {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get('code');
    if (code) {
        fetch('https://your-server.com/oauth/callback', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ code }),
        })
        .then(response => response.json())
        .then(data => {
            const accessToken = data.access_token;
            localStorage.setItem('github_token', accessToken);
            loadRepositories();
        });
    }
}
urlParams:這段程式碼用來從 URL 中擷取查詢參數,並取得 GitHub 發送回來的授權碼(code)。fetch:將授權碼發送到後端伺服器,後端伺服器會用該授權碼請求存取令牌(access_token)。localStorage.setItem:將從 GitHub 獲取的 access_token 存儲在瀏覽器的 localStorage 中,供後續的 API 請求使用。loadRepositories:當成功獲得存取令牌後,自動載入使用者的儲存庫列表。loadRepositories 函數)這個函數使用 GitHub API 來取得使用者的儲存庫列表,並顯示在網頁上。
function loadRepositories() {
    const token = localStorage.getItem('github_token');
    fetch('https://api.github.com/user/repos', {
        headers: {
            Authorization: `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(repos => {
        const repoList = document.getElementById('repo-list');
        repoList.innerHTML = '';  // 清空列表
        repos.forEach(repo => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `<a href="#" onclick="loadCommits('${repo.full_name}')">${repo.name}</a>`;
            repoList.appendChild(listItem);
        });
    });
}
localStorage.getItem('github_token'):從 localStorage 中獲取存取令牌。fetch:向 GitHub API 發送 GET 請求來獲取使用者的儲存庫列表。API URL 是 https://api.github.com/user/repos,而存取令牌被作為 Authorization 標頭的一部分發送(Bearer 認證模式)。repos:API 回應的是一個儲存庫的列表。repoList.innerHTML = '';:清空現有的列表。forEach:遍歷回應的儲存庫列表,並將每個儲存庫添加到頁面上作為連結。點擊連結時會加載該儲存庫的提交紀錄。loadCommits 函數)當使用者點擊某個儲存庫名稱時,這個函數會使用 GitHub API 來載入該儲存庫的提交紀錄。
function loadCommits(repoFullName) {
    const token = localStorage.getItem('github_token');
    fetch(`https://api.github.com/repos/${repoFullName}/commits`, {
        headers: {
            Authorization: `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(commits => {
        const commitList = document.getElementById('commit-list');
        commitList.innerHTML = '';  // 清空提交紀錄列表
        commits.forEach(commit => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `${commit.commit.author.name}: ${commit.commit.message}`;
            commitList.appendChild(listItem);
        });
    });
}
repoFullName:儲存庫的完整名稱(包括擁有者和儲存庫名稱),例如 username/repository。fetch:這裡我們使用 GitHub API 來取得特定儲存庫的提交紀錄。API URL 是 https://api.github.com/repos/${repoFullName}/commits。commits:API 回應的是該儲存庫的提交紀錄列表。forEach:遍歷提交紀錄,將每個提交的作者名稱和提交訊息顯示在頁面上。loadIssues 和 createIssue 函數)這兩個函數分別用於載入儲存庫的 issue 和建立新的 issue。
function loadIssues(repoFullName) {
    const token = localStorage.getItem('github_token');
    fetch(`https://api.github.com/repos/${repoFullName}/issues`, {
        headers: {
            Authorization: `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(issues => {
        const issueList = document.getElementById('issue-list');
        issueList.innerHTML = '';  // 清空 issue 列表
        issues.forEach(issue => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `${issue.title}: ${issue.body}`;
            issueList.appendChild(listItem);
        });
    });
}
function createIssue(repoFullName, issueTitle, issueBody) {
    const token = localStorage.getItem('github_token');
    fetch(`https://api.github.com/repos/${repoFullName}/issues`, {
        method: 'POST',
        headers: {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            title: issueTitle,
            body: issueBody
        })
    })
    .then(response => response.json())
    .then(issue => {
        alert(`Issue created: ${issue.title}`);
        loadIssues(repoFullName);  // 更新 issue 列表
    });
}
loadIssues:這個函數用來從 GitHub API 中獲取儲存庫的所有 issue,並顯示在頁面上。createIssue:這個函數用來建立新 issue。使用 POST 方法向 GitHub API 發送請求,並在主體中傳送 issue 的標題和內容。最後
,這段程式碼包含了簡單的前端 HTML,用來顯示儲存庫、提交紀錄和 issue。
<ul id="repo-list"></ul>
<ul id="commit-list"></ul>
<ul id="issue-list"></ul>
repo-list:用來顯示使用者的 GitHub 儲存庫列表。commit-list:用來顯示儲存庫的提交紀錄。issue-list:用來顯示儲存庫的 issue。這個程式碼展示了如何使用 GitHub OAuth 來實現授權,並透過 GitHub API 獲取使用者的儲存庫、提交紀錄和 issue。