From 0e29772f844fc641ca4156aa9d9a2400aa5e6d8f Mon Sep 17 00:00:00 2001 From: Brian Douglas Date: Mon, 1 May 2023 02:36:25 +0000 Subject: [PATCH 01/14] chore(patch): release 1.0.0-beta.6 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.6](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2023-05-01) ### 🐛 Bug Fixes * unrecognized-manifest-key ([#55](https://github.com/open-sauced/browser-extensions/issues/55)) ([d622500](https://github.com/open-sauced/browser-extensions/commit/d6225003fd3bcf5b16ab7c5113c6e559e5a50849)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f36eb..0617905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.6](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2023-05-01) + + +### 🐛 Bug Fixes + +* unrecognized-manifest-key ([#55](https://github.com/open-sauced/browser-extensions/issues/55)) ([d622500](https://github.com/open-sauced/browser-extensions/commit/d6225003fd3bcf5b16ab7c5113c6e559e5a50849)) + ## [1.0.0-beta.5](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2023-04-29) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 41ad045..d268085 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.5", + "version": "1.0.0-beta.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.5", + "version": "1.0.0-beta.6", "dependencies": { "@types/chrome": "^0.0.231", "react": "^18.0.0", diff --git a/package.json b/package.json index cbabbe5..834c46c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.5", + "version": "1.0.0-beta.6", "files": [ "dist" ], From 34e1f5aa64722759c1e17996cdaa9a00ea069eb0 Mon Sep 17 00:00:00 2001 From: zer0and1 Date: Tue, 2 May 2023 21:16:06 +0530 Subject: [PATCH 02/14] refactor: improved-auth-strategy (#56) * refactor: improved-auth-strategy * chore: refactored err handling * feat: Link to OpenSauced on avatar click --- manifest.json | 7 +----- src/constants.ts | 8 +++--- src/content-scripts/hotOSHomePage.ts | 32 ------------------------ src/pages/profile.tsx | 11 +++++++-- src/utils/checkAuthentication.ts | 33 +++++++++++++++++++++++++ src/utils/getAccessToken.ts | 13 ---------- src/worker/background.ts | 37 +++++++++------------------- 7 files changed, 57 insertions(+), 84 deletions(-) delete mode 100644 src/content-scripts/hotOSHomePage.ts create mode 100644 src/utils/checkAuthentication.ts delete mode 100644 src/utils/getAccessToken.ts diff --git a/manifest.json b/manifest.json index 087bbd3..19b7ed9 100644 --- a/manifest.json +++ b/manifest.json @@ -7,11 +7,6 @@ { "js": ["src/content-scripts/profileScreen.ts"], "matches": ["https://github.com/*"] - }, - { - "js": ["src/content-scripts/hotOSHomePage.ts"], - "matches": ["https://hot.opensauced.pizza/*"], - "run_at": "document_end" } ], "background": { @@ -25,5 +20,5 @@ "128": "src/assets/os-icons/os-icon-128.png" }, "host_permissions": [""], - "permissions": ["storage","webRequest", "tabs", "cookies"] + "permissions": ["storage", "tabs", "cookies"] } diff --git a/src/constants.ts b/src/constants.ts index 1209642..80bff6d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,10 +1,8 @@ -export const SUPABASE_LOCAL_STORAGE_KEY = "supabase.auth.token"; -export const SUPABASE_AUTH_DOMAIN = "ibcwmlhcimymasokhgvn.supabase.co"; -export const SUPABASE_COOKIE_NAME = "sb-access-token"; -export const SUPABASE_LOGIN_URL = "https://ibcwmlhcimymasokhgvn.supabase.co/auth/v1/authorize?provider=github&redirect_to=https://hot.opensauced.pizza/"; -export const SUPABASE_LOGOUT_URL = "https://ibcwmlhcimymasokhgvn.supabase.co/auth/v1/logout"; +export const SUPABASE_LOGIN_URL = "https://ibcwmlhcimymasokhgvn.supabase.co/auth/v1/authorize?provider=github&redirect_to=https://insights.opensauced.pizza/"; +export const SUPABASE_AUTH_COOKIE_NAME = "supabase-auth-token"; export const OPEN_SAUCED_AUTH_TOKEN_KEY = "os-access-token"; export const OPEN_SAUCED_USERS_ENDPOINT = "https://api.opensauced.pizza/v1/users"; export const OPEN_SAUCED_SESSION_ENDPOINT = "https://api.opensauced.pizza/v1/auth/session"; +export const OPEN_SAUCED_INSIGHTS_DOMAIN = "insights.opensauced.pizza"; export const GITHUB_PROFILE_MENU_SELECTOR = ".p-nickname.vcard-username.d-block"; export const GITHUB_PROFILE_EDIT_MENU_SELECTOR = "button.js-profile-editable-edit-button"; diff --git a/src/content-scripts/hotOSHomePage.ts b/src/content-scripts/hotOSHomePage.ts deleted file mode 100644 index 4d1a2ab..0000000 --- a/src/content-scripts/hotOSHomePage.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { checkTokenValidity } from "../utils/fetchOpenSaucedApiData"; -import getAccessToken from "../utils/getAccessToken"; -import setAccessTokenInChromeStorage from "../utils/setAccessToken"; -import { OPEN_SAUCED_AUTH_TOKEN_KEY } from "../constants"; - -const processHotOSHomePage = async () => { - const data = await chrome.storage.sync.get([OPEN_SAUCED_AUTH_TOKEN_KEY]); - - if (data[OPEN_SAUCED_AUTH_TOKEN_KEY]) { - return; -} - try { - const accessToken = getAccessToken(); - - if (!accessToken) { - return; -} - - const isValid = await checkTokenValidity(accessToken); - - if (!isValid) { - return; -} - - await setAccessTokenInChromeStorage(accessToken); - } catch (error) { - console.error("Error processing Hot home page:", error); - } -}; - -// the local storage takes time to set after the document is idle -setTimeout(processHotOSHomePage, 1000); diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index 36d5069..c16abef 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -80,6 +80,12 @@ export const Profile = () => {
+ User avatar { @ {page.props.userName}

+
{(user?.linkedin_url || user?.twitter_username) &&
{user.linkedin_url && { {user.twitter_username && { + chrome.cookies.get( + { + name: SUPABASE_AUTH_COOKIE_NAME, + url: `https://${OPEN_SAUCED_INSIGHTS_DOMAIN}`, + }, + async cookie => { + if (!cookie) { + return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY); + } + try { + const authCookie = JSON.parse(decodeURIComponent(cookie.value))[0]; + const isValidToken = await checkTokenValidity(authCookie); + + if (!isValidToken) { + return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY); + } + void setAccessTokenInChromeStorage(authCookie); + } catch (error) { + void chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY); + console.error("Error processing cookie:", error); + } + }, + ); +}; diff --git a/src/utils/getAccessToken.ts b/src/utils/getAccessToken.ts deleted file mode 100644 index 951433e..0000000 --- a/src/utils/getAccessToken.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SUPABASE_LOCAL_STORAGE_KEY } from "../constants"; - -const getAccessToken = (): string | null => { - const localStore = window.localStorage.getItem(SUPABASE_LOCAL_STORAGE_KEY); - - if (localStore === null) { - return null; -} - return JSON.parse(localStore)?.currentSession?.access_token; - }; - - export default getAccessToken; - diff --git a/src/worker/background.ts b/src/worker/background.ts index 2977019..82033f5 100644 --- a/src/worker/background.ts +++ b/src/worker/background.ts @@ -1,13 +1,5 @@ -import { SUPABASE_LOGOUT_URL, SUPABASE_AUTH_DOMAIN, SUPABASE_COOKIE_NAME, OPEN_SAUCED_AUTH_TOKEN_KEY } from "../constants"; -import { checkTokenValidity } from "../utils/fetchOpenSaucedApiData"; -import setAccessTokenInChromeStorage from "../utils/setAccessToken"; - -chrome.webRequest.onCompleted.addListener( - () => { - void chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY); - }, - { urls: [SUPABASE_LOGOUT_URL] }, -); +import { checkAuthentication } from "../utils/checkAuthentication"; +import { SUPABASE_AUTH_COOKIE_NAME, OPEN_SAUCED_INSIGHTS_DOMAIN } from "../constants"; chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { if (changeInfo.url?.includes("github.com")) { @@ -15,21 +7,14 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { } }); -chrome.cookies.onChanged.addListener(async changeInfo => { - try { - if (changeInfo.cookie.name !== SUPABASE_COOKIE_NAME || changeInfo.cookie.domain !== SUPABASE_AUTH_DOMAIN) { - return; - } - if (changeInfo.removed) { - return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY); - } - const isValidToken = await checkTokenValidity(changeInfo.cookie.value); - - if (!isValidToken) { - return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY); +chrome.cookies.onChanged.addListener(changeInfo => { + if ( + changeInfo.cookie.name === SUPABASE_AUTH_COOKIE_NAME || + changeInfo.cookie.domain === OPEN_SAUCED_INSIGHTS_DOMAIN + ) { + checkAuthentication(); } - void setAccessTokenInChromeStorage(changeInfo.cookie.value); - } catch (error) { - console.error("Error processing cookie update:", error); - } }); + +chrome.runtime.onInstalled.addListener(checkAuthentication); +chrome.runtime.onStartup.addListener(checkAuthentication); From 6348b3052e61a573a2303f5d6807fa56275a8f95 Mon Sep 17 00:00:00 2001 From: zer0and1 Date: Tue, 2 May 2023 15:47:09 +0000 Subject: [PATCH 03/14] chore(patch): release 1.0.0-beta.7 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.7](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2023-05-02) ### 🧑‍💻 Code Refactoring * improved-auth-strategy ([#56](https://github.com/open-sauced/browser-extensions/issues/56)) ([d8b27c3](https://github.com/open-sauced/browser-extensions/commit/d8b27c3e8a4259a4f40086feaf5e229a95fb59e9)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0617905..902de1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.7](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2023-05-02) + + +### 🧑‍💻 Code Refactoring + +* improved-auth-strategy ([#56](https://github.com/open-sauced/browser-extensions/issues/56)) ([d8b27c3](https://github.com/open-sauced/browser-extensions/commit/d8b27c3e8a4259a4f40086feaf5e229a95fb59e9)) + ## [1.0.0-beta.6](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2023-05-01) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d268085..95f9539 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "dependencies": { "@types/chrome": "^0.0.231", "react": "^18.0.0", diff --git a/package.json b/package.json index 834c46c..34f046b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "files": [ "dist" ], From ad17a14b2db1121e1a8af321c3ac1ad834d62030 Mon Sep 17 00:00:00 2001 From: zer0and1 Date: Thu, 4 May 2023 20:11:37 +0530 Subject: [PATCH 04/14] feat: add to highlights button (#64) * feat: add-to-highlights-button * feat: improved-dom-update-watcher * chore: formatting * refactor: replace profileScreen.ts with github.ts * refactor: parameterize delayInMs for reuse, implicit inference * chore: 25ms delay for github.ts domupdate * docs: Add documentation link README.md --- README.md | 6 ++- manifest.json | 5 +- src/constants.ts | 3 ++ .../AddPRToHighlightsButton.ts | 15 ++++++ .../InviteToOpenSaucedModal.ts | 6 +-- src/content-scripts/github.ts | 36 +++++++++++++ src/content-scripts/profileScreen.ts | 32 ------------ src/utils/checkAuthentication.ts | 6 +++ src/utils/createHtmlElement.ts | 2 +- src/utils/dom-utils/addPRToHighlights.ts | 40 +++++++++++++++ src/utils/dom-utils/domUpdateWatcher.ts | 21 ++++++++ src/utils/dom-utils/inviteToOpenSauced.ts | 50 +++++++------------ src/utils/dom-utils/viewOnOpenSauced.ts | 7 +-- src/utils/urlMatchers.ts | 12 +++++ src/worker/background.ts | 6 --- 15 files changed, 164 insertions(+), 83 deletions(-) create mode 100644 src/content-scripts/components/AddPRToHighlights/AddPRToHighlightsButton.ts create mode 100644 src/content-scripts/github.ts delete mode 100644 src/content-scripts/profileScreen.ts create mode 100644 src/utils/dom-utils/addPRToHighlights.ts create mode 100644 src/utils/dom-utils/domUpdateWatcher.ts diff --git a/README.md b/README.md index ecc6910..04ccc10 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@

+## Documentation + +The documentation for the project can be found [here](https://docs.opensauced.pizza/chrome-extension/introduction-to-the-chrome-extension/). + ## Running the project locally To run the project, you'll need the following software binaries installed on your development machines: @@ -36,7 +40,7 @@ To run a local instance of the project: npm run dev ``` -## Installing the extension on a Chromium based browser: +## Installing the local build on a Chromium based browser: After running the above commands, 1. Navigate to `chrome://extensions`. 2. Enable the `Developer Mode`. diff --git a/manifest.json b/manifest.json index 19b7ed9..3a32a3a 100644 --- a/manifest.json +++ b/manifest.json @@ -5,8 +5,9 @@ "action": { "default_popup": "index.html" }, "content_scripts": [ { - "js": ["src/content-scripts/profileScreen.ts"], - "matches": ["https://github.com/*"] + "js": ["src/content-scripts/github.ts"], + "matches": ["https://github.com/*"], + "run": "document_end" } ], "background": { diff --git a/src/constants.ts b/src/constants.ts index 80bff6d..d6f628b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,3 +6,6 @@ export const OPEN_SAUCED_SESSION_ENDPOINT = "https://api.opensauced.pizza/v1/aut export const OPEN_SAUCED_INSIGHTS_DOMAIN = "insights.opensauced.pizza"; export const GITHUB_PROFILE_MENU_SELECTOR = ".p-nickname.vcard-username.d-block"; export const GITHUB_PROFILE_EDIT_MENU_SELECTOR = "button.js-profile-editable-edit-button"; +export const GITHUB_PR_AUTHOR_USERNAME_SELECTOR = "author Link--primary text-bold css-overflow-wrap-anywhere"; +export const GITHUB_LOGGED_IN_USER_USERNAME_SELECTOR = "meta[name=\"user-login\"]"; +export const GITHUB_PR_COMMENT_HEADER_SELECTOR = "timeline-comment-header clearfix d-flex"; diff --git a/src/content-scripts/components/AddPRToHighlights/AddPRToHighlightsButton.ts b/src/content-scripts/components/AddPRToHighlights/AddPRToHighlightsButton.ts new file mode 100644 index 0000000..d2d464d --- /dev/null +++ b/src/content-scripts/components/AddPRToHighlights/AddPRToHighlightsButton.ts @@ -0,0 +1,15 @@ +import { createHtmlElement } from "../../../utils/createHtmlElement"; +import openSaucedLogoIcon from "../../../assets/opensauced-icon.svg"; + +export const AddPRToHighlightsButton = () => { + const addPRToHighlightsButton = createHtmlElement("a", { + href: `https://insights.opensauced.pizza/feed?url=${encodeURIComponent(window.location.href)}`, + target: "_blank", + rel: "noopener noreferrer", + innerHTML: ` + + `, + }); + + return addPRToHighlightsButton; +}; diff --git a/src/content-scripts/components/InviteToOpenSauced/InviteToOpenSaucedModal.ts b/src/content-scripts/components/InviteToOpenSauced/InviteToOpenSaucedModal.ts index 67e33f3..fad9ca7 100644 --- a/src/content-scripts/components/InviteToOpenSauced/InviteToOpenSaucedModal.ts +++ b/src/content-scripts/components/InviteToOpenSauced/InviteToOpenSaucedModal.ts @@ -5,9 +5,9 @@ import twitterSocialIcon from "../../../assets/twitter-icon.svg"; import linkedInSocailIcon from "../../../assets/linkedin-icon.svg"; interface Socials { - emailAddress?: string; - twitterUsername?: string; - linkedInUsername?: string; + emailAddress?: string | null; + twitterUsername?: string | null; + linkedInUsername?: string | null; } export const InviteToOpenSaucedModal = ( diff --git a/src/content-scripts/github.ts b/src/content-scripts/github.ts new file mode 100644 index 0000000..f9d29d0 --- /dev/null +++ b/src/content-scripts/github.ts @@ -0,0 +1,36 @@ +import { + getGithubUsername, + isGithubProfilePage, + isGithubPullRequestPage, +} from "../utils/urlMatchers"; +import { isOpenSaucedUser } from "../utils/fetchOpenSaucedApiData"; +import injectViewOnOpenSauced from "../utils/dom-utils/viewOnOpenSauced"; +import injectInviteToOpenSauced from "../utils/dom-utils/inviteToOpenSauced"; +import { prefersDarkMode } from "../utils/colorPreference"; +import injectAddPRToHighlightsButton from "../utils/dom-utils/addPRToHighlights"; +import domUpdateWatch from "../utils/dom-utils/domUpdateWatcher"; + +const processGithubPage = async () => { + if (prefersDarkMode(document.cookie)) { + document.documentElement.classList.add("dark"); + } + + if (isGithubPullRequestPage(window.location.href)) { + injectAddPRToHighlightsButton(); + } else if (isGithubProfilePage(window.location.href)) { + const username = getGithubUsername(window.location.href); + + if (!username) { + return; + } + if (await isOpenSaucedUser(username)) { + injectViewOnOpenSauced(username); + } else { + injectInviteToOpenSauced(username); + } + } + + domUpdateWatch(processGithubPage, 25); +}; + +void processGithubPage(); diff --git a/src/content-scripts/profileScreen.ts b/src/content-scripts/profileScreen.ts deleted file mode 100644 index e0112d1..0000000 --- a/src/content-scripts/profileScreen.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { getGithubUsername } from "../utils/urlMatchers"; -import { isOpenSaucedUser } from "../utils/fetchOpenSaucedApiData"; -import injectViewOnOpenSauced from "../utils/dom-utils/viewOnOpenSauced"; -import injectInviteToOpenSauced from "../utils/dom-utils/inviteToOpenSauced"; -import { prefersDarkMode } from "../utils/colorPreference"; - -const processProfilePage = async () => { - const username = getGithubUsername(window.location.href); - - if (username) { - const darkMode = prefersDarkMode(document.cookie); - - if (darkMode) { - document.documentElement.classList.add("dark"); -} - const user = await isOpenSaucedUser(username); - - if (user) { - injectViewOnOpenSauced(username); -} else { - injectInviteToOpenSauced(username); -} - } -}; - -chrome.runtime.onMessage.addListener(request => { - if (request.message === "GITHUB_URL_CHANGED") { - void processProfilePage(); - } -}); - -void processProfilePage(); diff --git a/src/utils/checkAuthentication.ts b/src/utils/checkAuthentication.ts index d289a4b..741b39e 100644 --- a/src/utils/checkAuthentication.ts +++ b/src/utils/checkAuthentication.ts @@ -31,3 +31,9 @@ export const checkAuthentication = () => { }, ); }; + +export const isLoggedIn = async () => + + // only a valid auth token can exist in the storage due to the check in line 23 + Object.entries(await chrome.storage.sync.get(OPEN_SAUCED_AUTH_TOKEN_KEY)).length !== 0; + diff --git a/src/utils/createHtmlElement.ts b/src/utils/createHtmlElement.ts index e1bfaab..98e613d 100644 --- a/src/utils/createHtmlElement.ts +++ b/src/utils/createHtmlElement.ts @@ -9,7 +9,7 @@ type CssDeclaration = keyof Omit; export function createHtmlElement ( nodeName: T, - props: ElementProps, + props: ElementProps = {}, ) { const { style, ...nonStyleProps } = props; const element = Object.assign(document.createElement(nodeName), nonStyleProps); diff --git a/src/utils/dom-utils/addPRToHighlights.ts b/src/utils/dom-utils/addPRToHighlights.ts new file mode 100644 index 0000000..909a786 --- /dev/null +++ b/src/utils/dom-utils/addPRToHighlights.ts @@ -0,0 +1,40 @@ +import { AddPRToHighlightsButton } from "../../content-scripts/components/AddPRToHighlights/AddPRToHighlightsButton"; +import { + GITHUB_LOGGED_IN_USER_USERNAME_SELECTOR, + GITHUB_PR_AUTHOR_USERNAME_SELECTOR, + GITHUB_PR_COMMENT_HEADER_SELECTOR, +} from "../../constants"; +import { isLoggedIn } from "../checkAuthentication"; + +const injectAddPRToHighlightsButton = async () => { + if (!(await isLoggedIn())) { + return; +} + + const prAuthorUserName = document.getElementsByClassName( + GITHUB_PR_AUTHOR_USERNAME_SELECTOR, + )[0].textContent; + const loggedInUserUserName = document + .querySelector(GITHUB_LOGGED_IN_USER_USERNAME_SELECTOR) + ?.getAttribute("content"); + + if (loggedInUserUserName && prAuthorUserName === loggedInUserUserName) { + const commentFormatRow = document.getElementsByClassName( + GITHUB_PR_COMMENT_HEADER_SELECTOR, + )[0]; + const addPRToHighlightsButton = AddPRToHighlightsButton(); + + if ( + !commentFormatRow.lastElementChild?.previousElementSibling?.isEqualNode( + addPRToHighlightsButton, + ) + ) { + commentFormatRow.insertBefore( + addPRToHighlightsButton, + commentFormatRow.lastElementChild, + ); + } + } +}; + +export default injectAddPRToHighlightsButton; diff --git a/src/utils/dom-utils/domUpdateWatcher.ts b/src/utils/dom-utils/domUpdateWatcher.ts new file mode 100644 index 0000000..88e288b --- /dev/null +++ b/src/utils/dom-utils/domUpdateWatcher.ts @@ -0,0 +1,21 @@ +const domUpdateWatch = (callback: () => void, delayInMs = 0) => { + const oldLocation = document.location.href; + const observer = new MutationObserver( + (_: unknown, observer: MutationObserver) => { + const newLocation = document.location.href; + + if (oldLocation === newLocation || document.readyState !== "complete") { + return; + } + observer.disconnect(); + setTimeout(callback, delayInMs); + }, + ); + + observer.observe(document.body, { + childList: true, + subtree: true, + }); +}; + +export default domUpdateWatch; diff --git a/src/utils/dom-utils/inviteToOpenSauced.ts b/src/utils/dom-utils/inviteToOpenSauced.ts index f63bc36..b4cdd35 100644 --- a/src/utils/dom-utils/inviteToOpenSauced.ts +++ b/src/utils/dom-utils/inviteToOpenSauced.ts @@ -4,34 +4,20 @@ import { InviteToOpenSaucedModal } from "../../content-scripts/components/Invite import { getTwitterUsername, getLinkedInUsername } from "../urlMatchers"; const injectOpenSaucedInviteButton = (username: string) => { - const emailAddress: string | undefined = (() => { - const element = document.querySelector(`a[href^="mailto:"]`); - - if (element instanceof HTMLAnchorElement) { - return element.href; - } - return undefined; - })(); - const twitterUrl: string | undefined = (() => { - const element = document.querySelector(`a[href*="twitter.com"]`); - - if (element instanceof HTMLAnchorElement) { - return element.href; - } - return undefined; - })(); - const linkedInUrl: string | undefined = (() => { - const element = document.querySelector(`a[href*="linkedin.com"]`); - - if (element instanceof HTMLAnchorElement) { - return element.href; - } - return undefined; - })(); + const emailAddress = document + .querySelector(`a[href^="mailto:"]`) + ?.getAttribute("href") + ?.replace("mailto:", ""); + const twitterUrl = document + .querySelector(`a[href*="twitter.com"]`) + ?.getAttribute("href"); + const linkedInUrl = document + .querySelector(`a[href*="linkedin.com"]`) + ?.getAttribute("href"); if (!(emailAddress || twitterUrl || linkedInUrl)) { - return; -} + return; + } const twitterUsername = twitterUrl && getTwitterUsername(twitterUrl); const linkedInUsername = linkedInUrl && getLinkedInUsername(linkedInUrl); @@ -48,13 +34,11 @@ const injectOpenSaucedInviteButton = (username: string) => { const userBio = document.querySelector(GITHUB_PROFILE_MENU_SELECTOR); - if (!userBio?.parentNode) { - return; -} - if (userBio.lastChild?.isEqualNode(inviteToOpenSaucedButton)) { - return; -} - userBio.append(inviteToOpenSaucedButton); + + if (userBio?.lastChild?.isEqualNode(inviteToOpenSaucedButton)) { + return; + } + userBio?.append(inviteToOpenSaucedButton); document.body.appendChild(inviteToOpenSaucedModal); }; diff --git a/src/utils/dom-utils/viewOnOpenSauced.ts b/src/utils/dom-utils/viewOnOpenSauced.ts index c545ebb..8741447 100644 --- a/src/utils/dom-utils/viewOnOpenSauced.ts +++ b/src/utils/dom-utils/viewOnOpenSauced.ts @@ -11,13 +11,10 @@ const injectViewOnOpenSaucedButton = (username: string) => { `${GITHUB_PROFILE_MENU_SELECTOR}, ${GITHUB_PROFILE_EDIT_MENU_SELECTOR}`, ); - if (!userBio?.parentNode) { + if (userBio?.lastChild?.isEqualNode(viewOnOpenSaucedButton)) { return; } - if (userBio.lastChild?.isEqualNode(viewOnOpenSaucedButton)) { - return; -} - userBio.append(viewOnOpenSaucedButton); + userBio?.append(viewOnOpenSaucedButton); }; export default injectViewOnOpenSaucedButton; diff --git a/src/utils/urlMatchers.ts b/src/utils/urlMatchers.ts index c46930c..6961d26 100644 --- a/src/utils/urlMatchers.ts +++ b/src/utils/urlMatchers.ts @@ -19,3 +19,15 @@ export const getTwitterUsername = (url: string) => { return match ? match[1] : undefined; }; + +export const isGithubPullRequestPage = (url: string) => { + const githubPullRequestPattern = /github\.com\/[\w.-]+\/[^/]+\/pull\/\d+/; + + return githubPullRequestPattern.test(url); +}; + +export const isGithubProfilePage = (url: string) => { + const githubProfilePattern = /github\.com\/[^/]+$/; + + return githubProfilePattern.test(url); +}; diff --git a/src/worker/background.ts b/src/worker/background.ts index 82033f5..a953bd5 100644 --- a/src/worker/background.ts +++ b/src/worker/background.ts @@ -1,12 +1,6 @@ import { checkAuthentication } from "../utils/checkAuthentication"; import { SUPABASE_AUTH_COOKIE_NAME, OPEN_SAUCED_INSIGHTS_DOMAIN } from "../constants"; -chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { - if (changeInfo.url?.includes("github.com")) { - void chrome.tabs.sendMessage(tabId, { message: "GITHUB_URL_CHANGED" }); - } -}); - chrome.cookies.onChanged.addListener(changeInfo => { if ( changeInfo.cookie.name === SUPABASE_AUTH_COOKIE_NAME || From ca3ac89c4e4741f3b921cb888fb6c25062ad1837 Mon Sep 17 00:00:00 2001 From: zer0and1 Date: Thu, 4 May 2023 14:42:42 +0000 Subject: [PATCH 05/14] chore(minor): release 1.0.0-beta.8 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.8](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2023-05-04) ### 🍕 Features * add to highlights button ([#64](https://github.com/open-sauced/browser-extensions/issues/64)) ([e2120a1](https://github.com/open-sauced/browser-extensions/commit/e2120a13d64fee2ab0867e5f17d647f64796467a)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902de1d..390a7d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.8](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2023-05-04) + + +### 🍕 Features + +* add to highlights button ([#64](https://github.com/open-sauced/browser-extensions/issues/64)) ([e2120a1](https://github.com/open-sauced/browser-extensions/commit/e2120a13d64fee2ab0867e5f17d647f64796467a)) + ## [1.0.0-beta.7](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2023-05-02) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 95f9539..6eeb736 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.7", + "version": "1.0.0-beta.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.7", + "version": "1.0.0-beta.8", "dependencies": { "@types/chrome": "^0.0.231", "react": "^18.0.0", diff --git a/package.json b/package.json index 34f046b..531cc51 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.7", + "version": "1.0.0-beta.8", "files": [ "dist" ], From 3d8618aa8381867899bb396f985dbe046ed64c6c Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Fri, 5 May 2023 16:59:33 +0530 Subject: [PATCH 06/14] fix: render emojis in user bio (#68) --- npm-shrinkwrap.json | 20 ++++++++++++++++++++ package.json | 2 ++ src/pages/profile.tsx | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 6eeb736..8f05c63 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -9,6 +9,8 @@ "version": "1.0.0-beta.8", "dependencies": { "@types/chrome": "^0.0.231", + "@types/node-emoji": "^1.8.2", + "node-emoji": "^1.11.0", "react": "^18.0.0", "react-dom": "^18.0.0", "react-icons": "^4.8.0" @@ -773,6 +775,11 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/node-emoji": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@types/node-emoji/-/node-emoji-1.8.2.tgz", + "integrity": "sha512-PfF1qL/9veo8BSHLV84C9ORNr3lHSlnWJ6yU8OdNufoftajeWHTLVbGHvp2B7e7DPDS9gMs6cfeSsqo5rqSitg==" + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -3654,6 +3661,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3795,6 +3807,14 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", diff --git a/package.json b/package.json index 531cc51..63dc6eb 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ }, "dependencies": { "@types/chrome": "^0.0.231", + "@types/node-emoji": "^1.8.2", + "node-emoji": "^1.11.0", "react": "^18.0.0", "react-dom": "^18.0.0", "react-icons": "^4.8.0" diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index c16abef..5fe0720 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -7,6 +7,7 @@ import { DiJava } from "react-icons/di"; import OpenSaucedLogo from "../assets/opensauced-logo.svg"; import { getUserData, getUserPRData } from "../utils/fetchOpenSaucedApiData"; import { RouteContext } from "../App"; +import { emojify } from "node-emoji"; const interestIcon = { python: , @@ -124,7 +125,7 @@ export const Profile = () => {
} {user?.bio && - {user.bio} + {emojify(user.bio)} } {user?.blog && From 121756b3a5e7396064056589aab4a48b4b6d6bac Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Fri, 5 May 2023 11:30:45 +0000 Subject: [PATCH 07/14] chore(patch): release 1.0.0-beta.9 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.9](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2023-05-05) ### 🐛 Bug Fixes * render emojis in user bio ([#68](https://github.com/open-sauced/browser-extensions/issues/68)) ([d0158a5](https://github.com/open-sauced/browser-extensions/commit/d0158a55fd49960d1f8d07af87d7621871965679)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 390a7d5..f726f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.9](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2023-05-05) + + +### 🐛 Bug Fixes + +* render emojis in user bio ([#68](https://github.com/open-sauced/browser-extensions/issues/68)) ([d0158a5](https://github.com/open-sauced/browser-extensions/commit/d0158a55fd49960d1f8d07af87d7621871965679)) + ## [1.0.0-beta.8](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2023-05-04) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 8f05c63..c894ab7 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "dependencies": { "@types/chrome": "^0.0.231", "@types/node-emoji": "^1.8.2", diff --git a/package.json b/package.json index 63dc6eb..1e7e666 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "files": [ "dist" ], From b2c02f56ef7ae2beea2c1d439d8c36c0cacb102f Mon Sep 17 00:00:00 2001 From: Ozgur Sar Date: Fri, 5 May 2023 21:06:35 +0300 Subject: [PATCH 08/14] fix username and avatar alignment (#69) --- src/pages/profile.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index 5fe0720..453bebe 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -82,7 +82,7 @@ export const Profile = () => {
{ />

- @ - {page.props.userName} + @{page.props.userName}

From 6b52b43daf10e2d94a8cee804130482cb80f68e1 Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Fri, 12 May 2023 22:38:08 +0530 Subject: [PATCH 09/14] feat: vote repos (#70) --- .eslintrc.js | 8 --- src/constants.ts | 9 +++- .../components/RepoVoting/RepoUnvoteButton.ts | 36 +++++++++++++ .../components/RepoVoting/RepoVoteButton.ts | 35 +++++++++++++ src/content-scripts/github.ts | 9 +++- src/utils/checkAuthentication.ts | 3 ++ src/utils/dom-utils/repoVotingButtons.ts | 42 +++++++++++++++ src/utils/fetchOpenSaucedApiData.ts | 51 ++++++++++++++++++- src/utils/urlMatchers.ts | 7 +++ 9 files changed, 189 insertions(+), 11 deletions(-) create mode 100644 src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts create mode 100644 src/content-scripts/components/RepoVoting/RepoVoteButton.ts create mode 100644 src/utils/dom-utils/repoVotingButtons.ts diff --git a/.eslintrc.js b/.eslintrc.js index 9a9d75a..23110d3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -43,14 +43,6 @@ module.exports = { rules: { // eslint:recommended "arrow-body-style": ["error", "as-needed"], - "capitalized-comments": [ - "error", - "never", - { - ignorePattern: "pragma|ignored", - ignoreInlineComments: true, - }, - ], curly: ["error", "all"], "dot-notation": "error", eqeqeq: ["error", "always"], diff --git a/src/constants.ts b/src/constants.ts index d6f628b..6c0e610 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,11 +1,18 @@ +// OpenSauced constants export const SUPABASE_LOGIN_URL = "https://ibcwmlhcimymasokhgvn.supabase.co/auth/v1/authorize?provider=github&redirect_to=https://insights.opensauced.pizza/"; export const SUPABASE_AUTH_COOKIE_NAME = "supabase-auth-token"; export const OPEN_SAUCED_AUTH_TOKEN_KEY = "os-access-token"; +export const OPEN_SAUCED_INSIGHTS_DOMAIN = "insights.opensauced.pizza"; + +// API endpoints export const OPEN_SAUCED_USERS_ENDPOINT = "https://api.opensauced.pizza/v1/users"; +export const OPEN_SAUCED_REPOS_ENDPOINT = "https://api.opensauced.pizza/v1/repos"; export const OPEN_SAUCED_SESSION_ENDPOINT = "https://api.opensauced.pizza/v1/auth/session"; -export const OPEN_SAUCED_INSIGHTS_DOMAIN = "insights.opensauced.pizza"; + +// GitHub constants/selectors export const GITHUB_PROFILE_MENU_SELECTOR = ".p-nickname.vcard-username.d-block"; export const GITHUB_PROFILE_EDIT_MENU_SELECTOR = "button.js-profile-editable-edit-button"; export const GITHUB_PR_AUTHOR_USERNAME_SELECTOR = "author Link--primary text-bold css-overflow-wrap-anywhere"; export const GITHUB_LOGGED_IN_USER_USERNAME_SELECTOR = "meta[name=\"user-login\"]"; export const GITHUB_PR_COMMENT_HEADER_SELECTOR = "timeline-comment-header clearfix d-flex"; +export const GITHUB_REPO_ACTIONS_SELECTOR = ".pagehead-actions"; diff --git a/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts b/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts new file mode 100644 index 0000000..c82c124 --- /dev/null +++ b/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts @@ -0,0 +1,36 @@ +import "../../content-scripts.css"; +import { createHtmlElement } from "../../../utils/createHtmlElement"; +import { getAuthToken } from "../../../utils/checkAuthentication"; +import { VoteRepoButton } from "./RepoVoteButton"; +import { voteOrUnvoteRepo } from "../../../utils/fetchOpenSaucedApiData"; + +export const RepoUnvoteButton = (ownerName: string, repoName: string) => { + const repoUnvoteButton = createHtmlElement("li", { + className: + "text-white text-center hover:shadow-button bg-gradient-to-r from-[#e67e22] to-[#d35400] btn btn-sm", + innerHTML: ` + Unvote + + `, + }); + + repoUnvoteButton.addEventListener("click", async () => { + repoUnvoteButton.innerHTML = ` + Loading... + `; + const userToken = await getAuthToken(); + + const unvoted = await voteOrUnvoteRepo(userToken, ownerName, repoName, false); + + if (unvoted) { + const voteRepoButton = VoteRepoButton(ownerName, repoName); + + repoUnvoteButton.replaceWith(voteRepoButton); + } else { + console.log("Something went wrong"); + } + }); + + + return repoUnvoteButton; +}; diff --git a/src/content-scripts/components/RepoVoting/RepoVoteButton.ts b/src/content-scripts/components/RepoVoting/RepoVoteButton.ts new file mode 100644 index 0000000..70b8e0f --- /dev/null +++ b/src/content-scripts/components/RepoVoting/RepoVoteButton.ts @@ -0,0 +1,35 @@ +import "../../content-scripts.css"; +import { createHtmlElement } from "../../../utils/createHtmlElement"; +import { getAuthToken } from "../../../utils/checkAuthentication"; +import { RepoUnvoteButton } from "./RepoUnvoteButton"; +import { voteOrUnvoteRepo } from "../../../utils/fetchOpenSaucedApiData"; + +export const VoteRepoButton = (ownerName: string, repoName: string) => { + const voteRepoButton = createHtmlElement("li", { + className: + "text-white text-center hover:shadow-button bg-gradient-to-r from-[#e67e22] to-[#d35400] btn btn-sm", + innerHTML: ` + Upvote + + `, + }); + + voteRepoButton.addEventListener("click", async () => { + voteRepoButton.innerHTML = ` + Loading... + `; + const userToken = await getAuthToken(); + + const voted = await voteOrUnvoteRepo(userToken, ownerName, repoName, false); + + if (voted) { + const unvoteRepoButton = RepoUnvoteButton(ownerName, repoName); + + voteRepoButton.replaceWith(unvoteRepoButton); + } else { + console.log("Something went wrong"); + } + }); + + return voteRepoButton; +}; diff --git a/src/content-scripts/github.ts b/src/content-scripts/github.ts index f9d29d0..fff6d6a 100644 --- a/src/content-scripts/github.ts +++ b/src/content-scripts/github.ts @@ -2,12 +2,14 @@ import { getGithubUsername, isGithubProfilePage, isGithubPullRequestPage, + isGithubRepoPage, } from "../utils/urlMatchers"; import { isOpenSaucedUser } from "../utils/fetchOpenSaucedApiData"; import injectViewOnOpenSauced from "../utils/dom-utils/viewOnOpenSauced"; import injectInviteToOpenSauced from "../utils/dom-utils/inviteToOpenSauced"; import { prefersDarkMode } from "../utils/colorPreference"; import injectAddPRToHighlightsButton from "../utils/dom-utils/addPRToHighlights"; +import injectRepoVotingButtons from "../utils/dom-utils/repoVotingButtons"; import domUpdateWatch from "../utils/dom-utils/domUpdateWatcher"; const processGithubPage = async () => { @@ -16,7 +18,7 @@ const processGithubPage = async () => { } if (isGithubPullRequestPage(window.location.href)) { - injectAddPRToHighlightsButton(); + await injectAddPRToHighlightsButton(); } else if (isGithubProfilePage(window.location.href)) { const username = getGithubUsername(window.location.href); @@ -28,6 +30,11 @@ const processGithubPage = async () => { } else { injectInviteToOpenSauced(username); } + } else if (isGithubRepoPage(window.location.href)) { + const ownerName = getGithubUsername(window.location.href) ?? ""; + const repoName = window.location.href.split("/").pop() ?? ""; + + await injectRepoVotingButtons(ownerName, repoName); } domUpdateWatch(processGithubPage, 25); diff --git a/src/utils/checkAuthentication.ts b/src/utils/checkAuthentication.ts index 741b39e..91959f1 100644 --- a/src/utils/checkAuthentication.ts +++ b/src/utils/checkAuthentication.ts @@ -37,3 +37,6 @@ export const isLoggedIn = async () => // only a valid auth token can exist in the storage due to the check in line 23 Object.entries(await chrome.storage.sync.get(OPEN_SAUCED_AUTH_TOKEN_KEY)).length !== 0; +export const getAuthToken = async () => (await chrome.storage.sync.get(OPEN_SAUCED_AUTH_TOKEN_KEY))[OPEN_SAUCED_AUTH_TOKEN_KEY]; + + diff --git a/src/utils/dom-utils/repoVotingButtons.ts b/src/utils/dom-utils/repoVotingButtons.ts new file mode 100644 index 0000000..effc7a9 --- /dev/null +++ b/src/utils/dom-utils/repoVotingButtons.ts @@ -0,0 +1,42 @@ +import { GITHUB_REPO_ACTIONS_SELECTOR } from "../../constants"; +import { VoteRepoButton } from "../../content-scripts/components/RepoVoting/RepoVoteButton"; +import { RepoUnvoteButton } from "../../content-scripts/components/RepoVoting/RepoUnvoteButton"; +import { isLoggedIn, getAuthToken } from "../checkAuthentication"; +import { + checkUserVotedRepo, + repoExistsOnOpenSauced, +} from "../fetchOpenSaucedApiData"; + +const injectRepoVotingButtons = async (ownerName: string, repoName: string) => { + if (!(await isLoggedIn())) { + return; + } + if (!(await repoExistsOnOpenSauced(ownerName, repoName))) { + return; + } + const repoActions = document.querySelector(GITHUB_REPO_ACTIONS_SELECTOR); + + if (!repoActions) { + return; + } + + const voteRepoButton = VoteRepoButton(ownerName, repoName); + const repoUnvoteButton = RepoUnvoteButton(ownerName, repoName); + const userToken = await getAuthToken(); + + const userVotedRepo = await checkUserVotedRepo(userToken, repoName); + + if (userVotedRepo) { + if (repoActions.lastChild?.isEqualNode(repoUnvoteButton)) { + return; + } + repoActions.appendChild(repoUnvoteButton); + } else { + if (repoActions.lastChild?.isEqualNode(voteRepoButton)) { + return; + } + repoActions.appendChild(voteRepoButton); + } +}; + +export default injectRepoVotingButtons; diff --git a/src/utils/fetchOpenSaucedApiData.ts b/src/utils/fetchOpenSaucedApiData.ts index 6509d38..2356ce4 100644 --- a/src/utils/fetchOpenSaucedApiData.ts +++ b/src/utils/fetchOpenSaucedApiData.ts @@ -1,5 +1,5 @@ import { cachedFetch } from "./cache"; -import { OPEN_SAUCED_USERS_ENDPOINT, OPEN_SAUCED_SESSION_ENDPOINT } from "../constants"; +import { OPEN_SAUCED_USERS_ENDPOINT, OPEN_SAUCED_SESSION_ENDPOINT, OPEN_SAUCED_REPOS_ENDPOINT } from "../constants"; export const isOpenSaucedUser = async (username: string) => { try { @@ -50,3 +50,52 @@ export const getUserPRData = async (userName: string, forceRefresh: boolean = fa return resp?.json(); }) .then(json => json); + +const getUserVotes = async (userToken: string, page: number = 1, limit: number = 1000, repos: any[] = []): Promise => { + const response = await fetch( + `${OPEN_SAUCED_REPOS_ENDPOINT}/listUserVoted?page=${page}&limit=${limit}`, + { + method: "GET", + headers: { Authorization: `Bearer ${userToken}` }, + }, + ); + + if (response.status === 200) { + const votesData = await response.json(); + + const newRepos = repos.concat(votesData.data); + + if (votesData.data.length === limit) { + return getUserVotes(userToken, page + 1, limit, newRepos); + } + return newRepos; + } + return repos; +}; + + +export const checkUserVotedRepo = async (userToken: string, repoName: string) => { + const userVotes = await getUserVotes(userToken); + + return userVotes.some((repo: any) => repo.name === repoName); +}; + +export const repoExistsOnOpenSauced = async (ownerName: string, repoName: string) => { + const response = await fetch( + `${OPEN_SAUCED_REPOS_ENDPOINT}/${ownerName}/${repoName}`, + ); + + return response.status === 200; +}; + +export const voteOrUnvoteRepo = async (userToken: string, ownerName: string, repoName: string, vote: boolean) => { + const response = await fetch( + `${OPEN_SAUCED_REPOS_ENDPOINT}/${ownerName}/${repoName}/vote`, + { + method: vote ? "POST" : "DELETE", + headers: { Authorization: `Bearer ${userToken}` }, + }, + ); + + return response.status === 200; +}; diff --git a/src/utils/urlMatchers.ts b/src/utils/urlMatchers.ts index 6961d26..9d3f893 100644 --- a/src/utils/urlMatchers.ts +++ b/src/utils/urlMatchers.ts @@ -31,3 +31,10 @@ export const isGithubProfilePage = (url: string) => { return githubProfilePattern.test(url); }; + + +export const isGithubRepoPage = (url: string) => { + const githubRepoPattern = /github\.com\/[^/]+\/[^/]+$/; + + return githubRepoPattern.test(url); +}; From d47ceb27842e5ac8347fe78a19b40aff16f0f6c9 Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Fri, 12 May 2023 17:10:27 +0000 Subject: [PATCH 10/14] chore(minor): release 1.0.0-beta.10 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.10](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.9...v1.0.0-beta.10) (2023-05-12) ### 🍕 Features * vote repos ([#70](https://github.com/open-sauced/browser-extensions/issues/70)) ([ff2c8f4](https://github.com/open-sauced/browser-extensions/commit/ff2c8f4198cd09fa8f591498298e6eddbc982c49)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f726f2c..d1a33f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.10](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.9...v1.0.0-beta.10) (2023-05-12) + + +### 🍕 Features + +* vote repos ([#70](https://github.com/open-sauced/browser-extensions/issues/70)) ([ff2c8f4](https://github.com/open-sauced/browser-extensions/commit/ff2c8f4198cd09fa8f591498298e6eddbc982c49)) + ## [1.0.0-beta.9](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2023-05-05) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c894ab7..e143128 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.9", + "version": "1.0.0-beta.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.9", + "version": "1.0.0-beta.10", "dependencies": { "@types/chrome": "^0.0.231", "@types/node-emoji": "^1.8.2", diff --git a/package.json b/package.json index 1e7e666..7a4a37e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.9", + "version": "1.0.0-beta.10", "files": [ "dist" ], From 437017cc3df271c44d2ef5635b0f84fbecaeb7ea Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Sat, 13 May 2023 13:08:16 +0530 Subject: [PATCH 11/14] fix: incorrect request for voting (#72) --- src/content-scripts/components/RepoVoting/RepoVoteButton.ts | 2 +- src/utils/fetchOpenSaucedApiData.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content-scripts/components/RepoVoting/RepoVoteButton.ts b/src/content-scripts/components/RepoVoting/RepoVoteButton.ts index 70b8e0f..a2bb43d 100644 --- a/src/content-scripts/components/RepoVoting/RepoVoteButton.ts +++ b/src/content-scripts/components/RepoVoting/RepoVoteButton.ts @@ -20,7 +20,7 @@ export const VoteRepoButton = (ownerName: string, repoName: string) => { `; const userToken = await getAuthToken(); - const voted = await voteOrUnvoteRepo(userToken, ownerName, repoName, false); + const voted = await voteOrUnvoteRepo(userToken, ownerName, repoName, true); if (voted) { const unvoteRepoButton = RepoUnvoteButton(ownerName, repoName); diff --git a/src/utils/fetchOpenSaucedApiData.ts b/src/utils/fetchOpenSaucedApiData.ts index 2356ce4..28685fb 100644 --- a/src/utils/fetchOpenSaucedApiData.ts +++ b/src/utils/fetchOpenSaucedApiData.ts @@ -92,7 +92,7 @@ export const voteOrUnvoteRepo = async (userToken: string, ownerName: string, rep const response = await fetch( `${OPEN_SAUCED_REPOS_ENDPOINT}/${ownerName}/${repoName}/vote`, { - method: vote ? "POST" : "DELETE", + method: vote ? "PUT" : "DELETE", headers: { Authorization: `Bearer ${userToken}` }, }, ); From fade79eec1d65518ffb80176cfaadccf0a1bbba3 Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Sat, 13 May 2023 07:39:20 +0000 Subject: [PATCH 12/14] chore(patch): release 1.0.0-beta.11 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.11](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.10...v1.0.0-beta.11) (2023-05-13) ### 🐛 Bug Fixes * incorrect request for voting ([#72](https://github.com/open-sauced/browser-extensions/issues/72)) ([7a35014](https://github.com/open-sauced/browser-extensions/commit/7a35014448fbf836702251176f54e4983f638bef)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1a33f0..9e21608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.11](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.10...v1.0.0-beta.11) (2023-05-13) + + +### 🐛 Bug Fixes + +* incorrect request for voting ([#72](https://github.com/open-sauced/browser-extensions/issues/72)) ([7a35014](https://github.com/open-sauced/browser-extensions/commit/7a35014448fbf836702251176f54e4983f638bef)) + ## [1.0.0-beta.10](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.9...v1.0.0-beta.10) (2023-05-12) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index e143128..45fc493 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.10", + "version": "1.0.0-beta.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.10", + "version": "1.0.0-beta.11", "dependencies": { "@types/chrome": "^0.0.231", "@types/node-emoji": "^1.8.2", diff --git a/package.json b/package.json index 7a4a37e..db3e51a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.10", + "version": "1.0.0-beta.11", "files": [ "dist" ], From 8a1dcdb2dc1b7968535cc8f1f7713768cee570d8 Mon Sep 17 00:00:00 2001 From: zer0and1 Date: Sat, 13 May 2023 16:47:10 +0530 Subject: [PATCH 13/14] fix: circular-deps in vote buttons --- .../components/RepoVoting/RepoUnvoteButton.ts | 7 +++---- .../components/RepoVoting/RepoVoteButton.ts | 8 +++----- src/utils/fetchOpenSaucedApiData.ts | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts b/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts index c82c124..aed7ba1 100644 --- a/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts +++ b/src/content-scripts/components/RepoVoting/RepoUnvoteButton.ts @@ -20,12 +20,11 @@ export const RepoUnvoteButton = (ownerName: string, repoName: string) => { `; const userToken = await getAuthToken(); - const unvoted = await voteOrUnvoteRepo(userToken, ownerName, repoName, false); + const unvoted = await voteOrUnvoteRepo(userToken, ownerName, repoName, "DELETE"); if (unvoted) { - const voteRepoButton = VoteRepoButton(ownerName, repoName); - - repoUnvoteButton.replaceWith(voteRepoButton); + const { VoteRepoButton } = await import("./RepoVoteButton"); + repoUnvoteButton.replaceWith(VoteRepoButton(ownerName, repoName)); } else { console.log("Something went wrong"); } diff --git a/src/content-scripts/components/RepoVoting/RepoVoteButton.ts b/src/content-scripts/components/RepoVoting/RepoVoteButton.ts index a2bb43d..b22dfd3 100644 --- a/src/content-scripts/components/RepoVoting/RepoVoteButton.ts +++ b/src/content-scripts/components/RepoVoting/RepoVoteButton.ts @@ -1,7 +1,6 @@ import "../../content-scripts.css"; import { createHtmlElement } from "../../../utils/createHtmlElement"; import { getAuthToken } from "../../../utils/checkAuthentication"; -import { RepoUnvoteButton } from "./RepoUnvoteButton"; import { voteOrUnvoteRepo } from "../../../utils/fetchOpenSaucedApiData"; export const VoteRepoButton = (ownerName: string, repoName: string) => { @@ -20,12 +19,11 @@ export const VoteRepoButton = (ownerName: string, repoName: string) => { `; const userToken = await getAuthToken(); - const voted = await voteOrUnvoteRepo(userToken, ownerName, repoName, true); + const voted = await voteOrUnvoteRepo(userToken, ownerName, repoName, "PUT"); if (voted) { - const unvoteRepoButton = RepoUnvoteButton(ownerName, repoName); - - voteRepoButton.replaceWith(unvoteRepoButton); + const { RepoUnvoteButton } = await import("./RepoUnvoteButton"); + voteRepoButton.replaceWith(RepoUnvoteButton(ownerName, repoName)); } else { console.log("Something went wrong"); } diff --git a/src/utils/fetchOpenSaucedApiData.ts b/src/utils/fetchOpenSaucedApiData.ts index 28685fb..78dfd14 100644 --- a/src/utils/fetchOpenSaucedApiData.ts +++ b/src/utils/fetchOpenSaucedApiData.ts @@ -88,11 +88,11 @@ export const repoExistsOnOpenSauced = async (ownerName: string, repoName: string return response.status === 200; }; -export const voteOrUnvoteRepo = async (userToken: string, ownerName: string, repoName: string, vote: boolean) => { +export const voteOrUnvoteRepo = async (userToken: string, ownerName: string, repoName: string, method: "PUT" | "DELETE") => { const response = await fetch( `${OPEN_SAUCED_REPOS_ENDPOINT}/${ownerName}/${repoName}/vote`, { - method: vote ? "PUT" : "DELETE", + method, headers: { Authorization: `Bearer ${userToken}` }, }, ); From 946f2bbda3d17a1344b390bd165508c981229c98 Mon Sep 17 00:00:00 2001 From: zer0and1 Date: Sat, 13 May 2023 11:38:28 +0000 Subject: [PATCH 14/14] chore(patch): release 1.0.0-beta.12 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.0.0-beta.12](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.11...v1.0.0-beta.12) (2023-05-13) ### 🐛 Bug Fixes * circular-deps in vote buttons ([675496c](https://github.com/open-sauced/browser-extensions/commit/675496cc3b3cbbb214c0ea77e49a059bc5ba6d7c)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e21608..5fb6fc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.0.0-beta.12](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.11...v1.0.0-beta.12) (2023-05-13) + + +### 🐛 Bug Fixes + +* circular-deps in vote buttons ([675496c](https://github.com/open-sauced/browser-extensions/commit/675496cc3b3cbbb214c0ea77e49a059bc5ba6d7c)) + ## [1.0.0-beta.11](https://github.com/open-sauced/browser-extensions/compare/v1.0.0-beta.10...v1.0.0-beta.11) (2023-05-13) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 45fc493..e0da368 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opensauced-browser-extension", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "dependencies": { "@types/chrome": "^0.0.231", "@types/node-emoji": "^1.8.2", diff --git a/package.json b/package.json index db3e51a..4b459df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opensauced-browser-extension", "private": true, - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "files": [ "dist" ],