diff --git a/src/home/authentication.ts b/src/home/authentication.ts index 7780dae6..4e8fb1ae 100644 --- a/src/home/authentication.ts +++ b/src/home/authentication.ts @@ -14,6 +14,6 @@ export async function authentication() { const gitHubUser: null | GitHubUser = await getGitHubUser(); if (gitHubUser) { trackDevRelReferral(gitHubUser.login + "|" + gitHubUser.id); - displayGitHubUserInformation(gitHubUser); + await displayGitHubUserInformation(gitHubUser); } } diff --git a/src/home/fetch-github/fetch-issues-preview.ts b/src/home/fetch-github/fetch-issues-preview.ts index 2820d206..fe75e99b 100644 --- a/src/home/fetch-github/fetch-issues-preview.ts +++ b/src/home/fetch-github/fetch-issues-preview.ts @@ -24,7 +24,7 @@ async function checkPrivateRepoAccess(): Promise { } return false; } catch (error) { - if (error instanceof RequestError && error.status === 404) { + if (!!error && typeof error === "object" && "status" in error && (error.status === 404 || error.status === 401)) { // If the status is 404, it means the user is not a collaborator, hence no access return false; } else { diff --git a/src/home/getters/get-github-access-token.ts b/src/home/getters/get-github-access-token.ts index 4e19f008..c5303f81 100644 --- a/src/home/getters/get-github-access-token.ts +++ b/src/home/getters/get-github-access-token.ts @@ -1,7 +1,31 @@ declare const SUPABASE_STORAGE_KEY: string; // @DEV: passed in at build time check build/esbuild-build.ts +import { Octokit } from "@octokit/rest"; import { checkSupabaseSession } from "../rendering/render-github-login-button"; import { getLocalStore } from "./get-local-store"; +/** + * Checks if the logged-in user is part of Ubiquity's Org, and didn't grant the 'repo' scope + */ +export async function isOrgMemberWithoutScope() { + const octokit = new Octokit({ auth: await getGitHubAccessToken() }); + try { + await octokit.orgs.getMembershipForAuthenticatedUser({ + org: "ubiquity", + }); + } catch (e) { + if (e && typeof e === "object" && "status" in e && e.status === 404) { + return false; + } + throw e; + } + const { headers } = await octokit.request("HEAD /"); + if (headers) { + const scopes = headers["x-oauth-scopes"]?.split(", "); + return !scopes?.includes("repo"); + } + return false; +} + export async function getGitHubAccessToken(): Promise { // better to use official function, looking up localstorage has flaws const oauthToken = await checkSupabaseSession(); diff --git a/src/home/rendering/display-github-user-information.ts b/src/home/rendering/display-github-user-information.ts index cb875733..398d3a5d 100644 --- a/src/home/rendering/display-github-user-information.ts +++ b/src/home/rendering/display-github-user-information.ts @@ -1,24 +1,27 @@ +import { isOrgMemberWithoutScope } from "../getters/get-github-access-token"; import { GitHubUser } from "../github-types"; -import { getSupabase } from "./render-github-login-button"; +import { getSupabase, renderAugmentAccessButton } from "./render-github-login-button"; -export function displayGitHubUserInformation(gitHubUser: GitHubUser) { +export async function displayGitHubUserInformation(gitHubUser: GitHubUser) { const toolbar = document.getElementById("toolbar"); - const authenticated = document.createElement("div"); - authenticated.id = "authenticated"; + const authenticatedDivElement = document.createElement("div"); + const containerDivElement = document.createElement("div"); + authenticatedDivElement.id = "authenticated"; + authenticatedDivElement.classList.add("user-container"); if (!toolbar) throw new Error("toolbar not found"); const img = document.createElement("img"); img.src = gitHubUser.avatar_url; img.alt = gitHubUser.login; - authenticated.appendChild(img); + authenticatedDivElement.appendChild(img); - const div = document.createElement("div"); + const divNameElement = document.createElement("div"); - div.textContent = gitHubUser.name; - div.classList.add("full"); - authenticated.appendChild(div); + divNameElement.textContent = gitHubUser.name; + divNameElement.classList.add("full"); + authenticatedDivElement.appendChild(divNameElement); - authenticated.addEventListener("click", async function signOut() { + authenticatedDivElement.addEventListener("click", async function signOut() { const supabase = getSupabase(); const { error } = await supabase.auth.signOut(); if (error) { @@ -28,7 +31,14 @@ export function displayGitHubUserInformation(gitHubUser: GitHubUser) { window.location.reload(); }); - toolbar.appendChild(authenticated); + containerDivElement.appendChild(authenticatedDivElement); + + if (await isOrgMemberWithoutScope()) { + const accessButton = renderAugmentAccessButton(); + containerDivElement.appendChild(accessButton); + } + + toolbar.appendChild(containerDivElement); toolbar.setAttribute("data-authenticated", "true"); toolbar.classList.add("ready"); } diff --git a/src/home/rendering/render-github-login-button.ts b/src/home/rendering/render-github-login-button.ts index a8b5f8f9..2cec107d 100644 --- a/src/home/rendering/render-github-login-button.ts +++ b/src/home/rendering/render-github-login-button.ts @@ -18,25 +18,35 @@ export async function checkSupabaseSession() { return session; } -async function gitHubLoginButtonHandler() { +async function gitHubLoginButtonHandler(scopes = "public_repo read:org") { const { error } = await supabase.auth.signInWithOAuth({ provider: "github", options: { - scopes: "repo", + scopes, }, }); if (error) { console.error("Error logging in:", error); } } + +const augmentAccessButton = document.createElement("button"); +export function renderAugmentAccessButton() { + augmentAccessButton.id = "augment-access-button"; + augmentAccessButton.innerHTML = ``; + augmentAccessButton.addEventListener("click", () => gitHubLoginButtonHandler("repo read:org")); + return augmentAccessButton; +} + const gitHubLoginButton = document.createElement("button"); export function renderGitHubLoginButton() { gitHubLoginButton.id = "github-login-button"; gitHubLoginButton.innerHTML = "Login With GitHub"; - gitHubLoginButton.addEventListener("click", gitHubLoginButtonHandler); + gitHubLoginButton.addEventListener("click", () => gitHubLoginButtonHandler()); if (toolbar) { toolbar.appendChild(gitHubLoginButton); toolbar.classList.add("ready"); } } + export { gitHubLoginButton }; diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index 339b33b1..7990a2e7 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -664,4 +664,14 @@ opacity: 0.5; } } + .svg-icon { + fill: #070707; + width: 24px; + height: 24px; + } + .user-container { + display: flex; + align-items: center; + margin-right: 8px; + } } diff --git a/static/style/style.css b/static/style/style.css index 1664c11a..942f24f8 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -664,4 +664,14 @@ opacity: 0.5; } } + .svg-icon { + fill: #f8f8f8; + width: 24px; + height: 24px; + } + .user-container { + display: flex; + align-items: center; + margin-right: 8px; + } }