diff --git a/manifest.json b/manifest.json index 795f250b..3ab39992 100644 --- a/manifest.json +++ b/manifest.json @@ -35,6 +35,7 @@ "https://practice.geeksforgeeks.org/*" ], "js": [ + "scripts/util.js", "scripts/leetcode.js", "scripts/authorize.js", "scripts/gfg.js" diff --git a/popup.html b/popup.html index 31791f1a..4835703e 100644 --- a/popup.html +++ b/popup.html @@ -117,6 +117,7 @@

+ diff --git a/popup.js b/popup.js index 2a243277..4d2fbe44 100644 --- a/popup.js +++ b/popup.js @@ -1,4 +1,4 @@ -/* global oAuth2 */ +/* global oAuth2, githubRequest, displayStats */ /* eslint no-undef: "error" */ let action = false; @@ -10,14 +10,8 @@ $('#authenticate').on('click', () => { }); /* Get URL for welcome page */ -$('#welcome_URL').attr( - 'href', - chrome.runtime.getURL('welcome.html') -); -$('#hook_URL').attr( - 'href', - chrome.runtime.getURL('welcome.html') -); +$('#welcome_URL').attr('href', chrome.runtime.getURL('welcome.html')); +$('#hook_URL').attr('href', chrome.runtime.getURL('welcome.html')); chrome.storage.local.get('leethub_token', (data) => { const token = data.leethub_token; @@ -25,13 +19,15 @@ chrome.storage.local.get('leethub_token', (data) => { action = true; $('#auth_mode').show(); } else { - // To validate user, load user object from GitHub. const AUTHENTICATION_URL = 'https://api.github.com/user'; - const xhr = new XMLHttpRequest(); - xhr.addEventListener('readystatechange', function () { - if (xhr.readyState === 4) { - if (xhr.status === 200) { + githubRequest( + 'GET', + AUTHENTICATION_URL, + token, + null, + (status) => { + if (status === 200) { /* Show MAIN FEATURES */ chrome.storage.local.get('mode_type', (data2) => { if (data2 && data2.mode_type === 'commit') { @@ -40,13 +36,7 @@ chrome.storage.local.get('leethub_token', (data) => { chrome.storage.local.get( ['stats', 'leethub_hook'], (data3) => { - const { stats } = data3; - if (stats && stats.solved) { - $('#p_solved').text(stats.solved); - $('#p_solved_easy').text(stats.easy); - $('#p_solved_medium').text(stats.medium); - $('#p_solved_hard').text(stats.hard); - } + displayStats(data3.stats); const leethubHook = data3.leethub_hook; if (leethubHook) { $('#repo_url').html( @@ -59,9 +49,7 @@ chrome.storage.local.get('leethub_token', (data) => { $('#hook_mode').show(); } }); - } else if (xhr.status === 401) { - // bad oAuth - // reset token and redirect to authorization process again! + } else if (status === 401) { chrome.storage.local.set({ leethub_token: null }, () => { console.log( 'BAD oAuth!!! Redirecting back to oAuth process', @@ -70,10 +58,7 @@ chrome.storage.local.get('leethub_token', (data) => { $('#auth_mode').show(); }); } - } - }); - xhr.open('GET', AUTHENTICATION_URL, true); - xhr.setRequestHeader('Authorization', `token ${token}`); - xhr.send(); + }, + ); } }); diff --git a/scripts/gfg.js b/scripts/gfg.js index c773c207..95f021a5 100644 --- a/scripts/gfg.js +++ b/scripts/gfg.js @@ -1,3 +1,5 @@ +/* global languages, getSHA, uploadGit, encodeToBase64 */ + /* Enum for languages supported by GeeksForGeeks. */ // const gfgLanguages = { // Python3: '.py', @@ -30,8 +32,9 @@ function findGfgLanguage() { } function findTitle() { - const ele = document.querySelector('[class^="problems_header_content__title"] > h3') - .innerText; + const ele = document.querySelector( + '[class^="problems_header_content__title"] > h3', + ).innerText; if (ele != null) { return ele; } @@ -39,7 +42,9 @@ function findTitle() { } function findDifficulty() { - const ele = document.querySelectorAll('[class^="problems_header_description"]')[0].children[0].innerText; + const ele = document.querySelectorAll( + '[class^="problems_header_description"]', + )[0].children[0].innerText; if (ele != null) { if (ele.trim() == 'Basic' || ele.trim() === 'School') { @@ -51,12 +56,13 @@ function findDifficulty() { } function getProblemStatement() { - const ele = document.querySelector('[class^="problems_problem_content"]'); + const ele = document.querySelector( + '[class^="problems_problem_content"]', + ); return `${ele.outerHTML}`; } function getCode() { - const scriptContent = ` var editor = ace.edit("ace-editor"); var editorContent = editor.getValue(); @@ -103,14 +109,22 @@ const gfgLoader = setInterval(() => { 'practice.geeksforgeeks.org/problems', ) ) { - - const submitBtn = document.evaluate(".//button[text()='Submit']", document.body, null, XPathResult.ANY_TYPE, null).iterateNext(); + const submitBtn = document + .evaluate( + ".//button[text()='Submit']", + document.body, + null, + XPathResult.ANY_TYPE, + null, + ) + .iterateNext(); submitBtn.addEventListener('click', function () { START_MONITOR = true; const submission = setInterval(() => { - const output = document.querySelectorAll('[class^="problems_content"]')[0] - .innerText; + const output = document.querySelectorAll( + '[class^="problems_content"]', + )[0].innerText; if ( output.includes('Problem Solved Successfully') && START_MONITOR @@ -137,19 +151,12 @@ const gfgLoader = setInterval(() => { const { stats } = s; const filePath = probName + toKebabCase(title + language); - let sha = null; - if ( - stats !== undefined && - stats.sha !== undefined && - stats.sha[filePath] !== undefined - ) { - sha = stats.sha[filePath]; - } + const sha = getSHA(stats, filePath); // Only create README if not already created // if (sha === null) { uploadGit( - btoa(unescape(encodeURIComponent(problemStatement))), + encodeToBase64(problemStatement), probName, 'README.md', README_MSG, @@ -163,7 +170,7 @@ const gfgLoader = setInterval(() => { if (code !== '') { setTimeout(function () { uploadGit( - btoa(unescape(encodeURIComponent(code))), + encodeToBase64(code), probName, toKebabCase(title + language), SUBMIT_MSG, diff --git a/scripts/leetcode.js b/scripts/leetcode.js index a4569f25..605c2dae 100644 --- a/scripts/leetcode.js +++ b/scripts/leetcode.js @@ -1,25 +1,5 @@ -/* Enum for languages supported by LeetCode. */ -const languages = { - Python: '.py', - Python3: '.py', - 'C++': '.cpp', - C: '.c', - Java: '.java', - 'C#': '.cs', - JavaScript: '.js', - Javascript: '.js', - Ruby: '.rb', - Swift: '.swift', - Go: '.go', - Kotlin: '.kt', - Scala: '.scala', - Rust: '.rs', - PHP: '.php', - TypeScript: '.ts', - MySQL: '.sql', - 'MS SQL Server': '.sql', - Oracle: '.sql', -}; +/* global checkElem, languages, convertToSlug, githubRequest, + createDefaultStats, decodeFromBase64, encodeToBase64, getSHA */ /* Commit messages */ const readmeMsg = 'Create README - LeetHub'; @@ -34,7 +14,7 @@ const EXPLORE_SECTION_PROBLEM = 1; let difficulty = ''; /* state of upload for progress */ -let uploadState = { uploading: false }; +const uploadState = { uploading: false }; /* Get file extension for submission */ function findLanguage() { @@ -66,63 +46,38 @@ const upload = ( msg, cb = undefined, ) => { - // To validate user, load user object from GitHub. const URL = `https://api.github.com/repos/${hook}/contents/${directory}/${filename}`; + const data = { message: msg, content: code, sha }; - /* Define Payload */ - let data = { - message: msg, - content: code, - sha, - }; - - data = JSON.stringify(data); - - const xhr = new XMLHttpRequest(); - xhr.addEventListener('readystatechange', function () { - if (xhr.readyState === 4) { - if (xhr.status === 200 || xhr.status === 201) { - const updatedSha = JSON.parse(xhr.responseText).content.sha; // get updated SHA. - - chrome.storage.local.get('stats', (data2) => { - let { stats } = data2; - if (stats === null || stats === {} || stats === undefined) { - // create stats object - stats = {}; - stats.solved = 0; - stats.easy = 0; - stats.medium = 0; - stats.hard = 0; - stats.sha = {}; - } - const filePath = directory + filename; - // Only increment solved problems statistics once - // New submission commits twice (README and problem) - if (filename === 'README.md' && sha === null) { - stats.solved += 1; - stats.easy += difficulty === 'Easy' ? 1 : 0; - stats.medium += difficulty === 'Medium' ? 1 : 0; - stats.hard += difficulty === 'Hard' ? 1 : 0; - } - stats.sha[filePath] = updatedSha; // update sha key. - chrome.storage.local.set({ stats }, () => { - console.log( - `Successfully committed ${filename} to github`, - ); + githubRequest('PUT', URL, token, data, (status, responseText) => { + if (status === 200 || status === 201) { + const updatedSha = JSON.parse(responseText).content.sha; - // if callback is defined, call it - if (cb !== undefined) { - cb(); - } - }); + chrome.storage.local.get('stats', (data2) => { + let { stats } = data2; + if (stats === null || stats === {} || stats === undefined) { + stats = createDefaultStats(); + } + const filePath = directory + filename; + // Only increment solved problems statistics once + // New submission commits twice (README and problem) + if (filename === 'README.md' && sha === null) { + stats.solved += 1; + stats.easy += difficulty === 'Easy' ? 1 : 0; + stats.medium += difficulty === 'Medium' ? 1 : 0; + stats.hard += difficulty === 'Hard' ? 1 : 0; + } + stats.sha[filePath] = updatedSha; + chrome.storage.local.set({ stats }, () => { + console.log(`Successfully committed ${filename} to github`); + + if (cb !== undefined) { + cb(); + } }); - } + }); } }); - xhr.open('PUT', URL, true); - xhr.setRequestHeader('Authorization', `token ${token}`); - xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json'); - xhr.send(data); }; /* Main function for updating code on GitHub Repo */ @@ -139,43 +94,28 @@ const update = ( ) => { const URL = `https://api.github.com/repos/${hook}/contents/${directory}/README.md`; - /* Read from existing file on GitHub */ - const xhr = new XMLHttpRequest(); - xhr.addEventListener('readystatechange', function () { - if (xhr.readyState === 4) { - if (xhr.status === 200 || xhr.status === 201) { - const response = JSON.parse(xhr.responseText); - const existingContent = decodeURIComponent( - escape(atob(response.content)), - ); - let newContent = ''; - - /* Discussion posts prepended at top of README */ - /* Future implementations may require appending to bottom of file */ - if (prepend) { - newContent = btoa( - unescape(encodeURIComponent(addition + existingContent)), - ); - } + githubRequest('GET', URL, token, null, (status, responseText) => { + if (status === 200 || status === 201) { + const response = JSON.parse(responseText); + const existingContent = decodeFromBase64(response.content); + let newContent = ''; - /* Write file with new content to GitHub */ - upload( - token, - hook, - newContent, - directory, - 'README.md', - response.sha, - msg, - cb, - ); + if (prepend) { + newContent = encodeToBase64(addition + existingContent); } + + upload( + token, + hook, + newContent, + directory, + 'README.md', + response.sha, + msg, + cb, + ); } }); - xhr.open('GET', URL, true); - xhr.setRequestHeader('Authorization', `token ${token}`); - xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json'); - xhr.send(); }; function uploadGit( @@ -205,20 +145,10 @@ function uploadGit( const hook = h.leethub_hook; if (hook) { /* Get SHA, if it exists */ - - /* to get unique key */ const filePath = problemName + fileName; chrome.storage.local.get('stats', (s) => { const { stats } = s; - let sha = null; - - if ( - stats !== undefined && - stats.sha !== undefined && - stats.sha[filePath] !== undefined - ) { - sha = stats.sha[filePath]; - } + const sha = getSHA(stats, filePath); if (action === 'upload') { /* Upload to git. */ @@ -267,14 +197,14 @@ function findCode( cb = undefined, ) { /* Get the submission details url from the submission page. */ - var submissionURL; + let submissionURL; const e = document.getElementsByClassName('status-column__3SUg'); if (checkElem(e)) { // for normal problem submisson const submissionRef = e[1].innerHTML.split(' ')[1]; - submissionURL = - 'https://leetcode.com' + - submissionRef.split('=')[1].slice(1, -1); + submissionURL = `https://leetcode.com${submissionRef + .split('=')[1] + .slice(1, -1)}`; } else { // for a submission in explore section const submissionRef = document.getElementById('result-state'); @@ -287,27 +217,27 @@ function findCode( xhttp.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { /* received submission details as html reponse. */ - var doc = new DOMParser().parseFromString( + const doc = new DOMParser().parseFromString( this.responseText, 'text/html', ); /* the response has a js object called pageData. */ /* Pagedata has the details data with code about that submission */ - var scripts = doc.getElementsByTagName('script'); - for (var i = 0; i < scripts.length; i++) { - var text = scripts[i].innerText; + const scripts = doc.getElementsByTagName('script'); + for (let i = 0; i < scripts.length; i++) { + const text = scripts[i].innerText; if (text.includes('pageData')) { /* Considering the pageData as text and extract the substring which has the full code */ - var firstIndex = text.indexOf('submissionCode'); - var lastIndex = text.indexOf('editCodeUrl'); - var slicedText = text.slice(firstIndex, lastIndex); + const firstIndex = text.indexOf('submissionCode'); + const lastIndex = text.indexOf('editCodeUrl'); + let slicedText = text.slice(firstIndex, lastIndex); /* slicedText has code as like as. (submissionCode: 'Details code'). */ /* So finding the index of first and last single inverted coma. */ - var firstInverted = slicedText.indexOf("'"); - var lastInverted = slicedText.lastIndexOf("'"); + const firstInverted = slicedText.indexOf("'"); + const lastInverted = slicedText.lastIndexOf("'"); /* Extract only the code */ - var codeUnicoded = slicedText.slice( + const codeUnicoded = slicedText.slice( firstInverted + 1, lastInverted, ); @@ -348,7 +278,7 @@ function findCode( if (code != null) { setTimeout(function () { uploadGit( - btoa(unescape(encodeURIComponent(code))), + encodeToBase64(code), problemName, fileName, msg, @@ -383,28 +313,6 @@ function parseCode() { return null; } -/* Util function to check if an element exists */ -function checkElem(elem) { - return elem && elem.length > 0; -} -function convertToSlug(string) { - const a = - 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;'; - const b = - 'aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------'; - const p = new RegExp(a.split('').join('|'), 'g'); - - return string - .toString() - .toLowerCase() - .replace(/\s+/g, '-') // Replace spaces with - - .replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters - .replace(/&/g, '-and-') // Replace & with 'and' - .replace(/[^\w\-]+/g, '') // Remove all non-word characters - .replace(/\-\-+/g, '-') // Replace multiple - with single - - .replace(/^-+/, '') // Trim - from start of text - .replace(/-+$/, ''); // Trim - from end of text -} function getProblemNameSlug() { const questionElem = document.getElementsByClassName( 'content__u3I1 question-content__JfgR', @@ -414,12 +322,12 @@ function getProblemNameSlug() { ); let questionTitle = 'unknown-problem'; if (checkElem(questionElem)) { - let qtitle = document.getElementsByClassName('css-v3d350'); + const qtitle = document.getElementsByClassName('css-v3d350'); if (checkElem(qtitle)) { questionTitle = qtitle[0].innerHTML; } } else if (checkElem(questionDescriptionElem)) { - let qtitle = document.getElementsByClassName('question-title'); + const qtitle = document.getElementsByClassName('question-title'); if (checkElem(qtitle)) { questionTitle = qtitle[0].innerText; } @@ -429,7 +337,7 @@ function getProblemNameSlug() { function addLeadingZeros(title) { const maxTitlePrefixLength = 4; - var len = title.split('-')[0].length; + const len = title.split('-')[0].length; if (len < maxTitlePrefixLength) { return '0'.repeat(4 - len) + title; } @@ -438,7 +346,7 @@ function addLeadingZeros(title) { /* Parser function for the question and tags */ function parseQuestion() { - var questionUrl = window.location.href; + let questionUrl = window.location.href; if (questionUrl.endsWith('/submissions/')) { questionUrl = questionUrl.substring( 0, @@ -477,7 +385,8 @@ function parseQuestion() { // Final formatting of the contents of the README for each problem const markdown = `

${qtitle}

${difficulty}


${qbody}`; return markdown; - } else if (checkElem(questionDescriptionElem)) { + } + if (checkElem(questionDescriptionElem)) { let questionTitle = document.getElementsByClassName( 'question-title', ); @@ -584,13 +493,13 @@ function getNotesIfAny() { } const loader = setInterval(() => { - let code = null; + const code = null; let probStatement = null; let probStats = null; let probType; const successTag = document.getElementsByClassName('success__3Ai7'); const resultState = document.getElementById('result-state'); - var success = false; + let success = false; // check success tag for a normal problem if ( checkElem(successTag) && @@ -638,20 +547,13 @@ const loader = setInterval(() => { chrome.storage.local.get('stats', (s) => { const { stats } = s; const filePath = problemName + problemName + language; - let sha = null; - if ( - stats !== undefined && - stats.sha !== undefined && - stats.sha[filePath] !== undefined - ) { - sha = stats.sha[filePath]; - } + const sha = getSHA(stats, filePath); /* Only create README if not already created */ if (sha === null) { /* @TODO: Change this setTimeout to Promise */ uploadGit( - btoa(unescape(encodeURIComponent(probStatement))), + encodeToBase64(probStatement), problemName, 'README.md', readmeMsg, @@ -669,7 +571,7 @@ const loader = setInterval(() => { console.log('Create Notes'); // means we can upload the notes too uploadGit( - btoa(unescape(encodeURIComponent(notes))), + encodeToBase64(notes), problemName, 'NOTES.md', createNotesMsg, @@ -689,9 +591,9 @@ const loader = setInterval(() => { 'upload', // callback is called when the code upload to git is a success () => { - if (uploadState['countdown']) - clearTimeout(uploadState['countdown']); - delete uploadState['countdown']; + if (uploadState.countdown) + clearTimeout(uploadState.countdown); + delete uploadState.countdown; uploadState.uploading = false; markUploaded(); }, @@ -705,7 +607,7 @@ const loader = setInterval(() => { /* we will start 10 seconds counter and even after that upload is not complete, then we conclude its failed */ function startUploadCountDown() { uploadState.uploading = true; - uploadState['countdown'] = setTimeout(() => { + uploadState.countdown = setTimeout(() => { if ((uploadState.uploading = true)) { // still uploading, then it failed uploadState.uploading = false; @@ -738,13 +640,13 @@ function insertToAnchorElement(elem) { if (target.childNodes.length > 0) target.childNodes[0].prepend(elem); } - } else { - if (checkElem(document.getElementsByClassName('action__38Xc'))) { - target = document.getElementsByClassName('action__38Xc')[0]; - elem.className = 'runcode-wrapper__8rXm'; - if (target.childNodes.length > 0) - target.childNodes[0].prepend(elem); - } + } else if ( + checkElem(document.getElementsByClassName('action__38Xc')) + ) { + target = document.getElementsByClassName('action__38Xc')[0]; + elem.className = 'runcode-wrapper__8rXm'; + if (target.childNodes.length > 0) + target.childNodes[0].prepend(elem); } } diff --git a/scripts/util.js b/scripts/util.js new file mode 100644 index 00000000..09a55bb4 --- /dev/null +++ b/scripts/util.js @@ -0,0 +1,120 @@ +/* eslint-disable no-unused-vars */ + +/* Util function to check if an element exists */ +function checkElem(elem) { + return elem && elem.length > 0; +} + +/* Encode a string to base64, handling Unicode characters */ +function encodeToBase64(str) { + return btoa(unescape(encodeURIComponent(str))); +} + +/* Decode a base64 string, handling Unicode characters */ +function decodeFromBase64(str) { + return decodeURIComponent(escape(atob(str))); +} + +/* Enum for languages supported by LeetCode and GeeksForGeeks */ +const languages = { + Python: '.py', + Python3: '.py', + 'C++': '.cpp', + C: '.c', + Java: '.java', + 'C#': '.cs', + JavaScript: '.js', + Javascript: '.js', + Ruby: '.rb', + Swift: '.swift', + Go: '.go', + Kotlin: '.kt', + Scala: '.scala', + Rust: '.rs', + PHP: '.php', + TypeScript: '.ts', + MySQL: '.sql', + 'MS SQL Server': '.sql', + Oracle: '.sql', +}; + +/* Convert a string to a URL-friendly slug */ +function convertToSlug(string) { + const a = + 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;'; + const b = + 'aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------'; + const p = new RegExp(a.split('').join('|'), 'g'); + + return string + .toString() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(p, (c) => b.charAt(a.indexOf(c))) + .replace(/&/g, '-and-') + .replace(/[^\w-]+/g, '') + .replace(/--+/g, '-') + .replace(/^-+/, '') + .replace(/-+$/, ''); +} + +/* Get SHA for a file path from stats, or null if not found */ +function getSHA(stats, filePath) { + if ( + stats !== undefined && + stats.sha !== undefined && + stats.sha[filePath] !== undefined + ) { + return stats.sha[filePath]; + } + return null; +} + +/* Create a default stats object */ +function createDefaultStats() { + return { solved: 0, easy: 0, medium: 0, hard: 0, sha: {} }; +} + +/* Make an authenticated GitHub API request */ +function githubRequest(method, url, token, data, callback) { + const xhr = new XMLHttpRequest(); + xhr.addEventListener('readystatechange', function () { + if (xhr.readyState === 4) { + callback(xhr.status, xhr.responseText); + } + }); + xhr.open(method, url, true); + xhr.setRequestHeader('Authorization', `token ${token}`); + xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json'); + if (data) { + xhr.send(typeof data === 'string' ? data : JSON.stringify(data)); + } else { + xhr.send(); + } +} + +/* Toggle display between hook_mode and commit_mode */ +function setDisplayMode(mode) { + const hookEl = document.getElementById('hook_mode'); + const commitEl = document.getElementById('commit_mode'); + if (hookEl) { + hookEl.style.display = mode === 'commit' ? 'none' : 'inherit'; + } + if (commitEl) { + commitEl.style.display = mode === 'commit' ? 'inherit' : 'none'; + } +} + +/* Display problem stats in the UI */ +function displayStats(stats) { + if (stats && stats.solved) { + const solvedEl = document.getElementById('p_solved'); + const easyEl = document.getElementById('p_solved_easy'); + const mediumEl = document.getElementById('p_solved_medium'); + const hardEl = document.getElementById('p_solved_hard'); + if (solvedEl) solvedEl.textContent = stats.solved; + if (easyEl) easyEl.textContent = stats.easy; + if (mediumEl) mediumEl.textContent = stats.medium; + if (hardEl) hardEl.textContent = stats.hard; + } +} diff --git a/scripts/welcome.js b/scripts/welcome.js index 9812db3c..17e04772 100644 --- a/scripts/welcome.js +++ b/scripts/welcome.js @@ -1,3 +1,5 @@ +/* global setDisplayMode, githubRequest, displayStats */ + const option = () => { return $('#type').val(); }; @@ -59,10 +61,7 @@ const statusCode = (res, status, name) => { ); $('#success').show(); $('#unlink').show(); - /* Show new layout */ - document.getElementById('hook_mode').style.display = 'none'; - document.getElementById('commit_mode').style.display = - 'inherit'; + setDisplayMode('commit'); }); /* Set Repo Hook */ chrome.storage.local.set( @@ -78,26 +77,23 @@ const statusCode = (res, status, name) => { const createRepo = (token, name) => { const AUTHENTICATION_URL = 'https://api.github.com/user/repos'; - let data = { + const data = { name, private: true, auto_init: true, description: 'Collection of LeetCode questions to ace the coding interview! - Created using [LeetHub](https://github.com/QasimWani/LeetHub)', }; - data = JSON.stringify(data); - - const xhr = new XMLHttpRequest(); - xhr.addEventListener('readystatechange', function () { - if (xhr.readyState === 4) { - statusCode(JSON.parse(xhr.responseText), xhr.status, name); - } - }); - xhr.open('POST', AUTHENTICATION_URL, true); - xhr.setRequestHeader('Authorization', `token ${token}`); - xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json'); - xhr.send(data); + githubRequest( + 'POST', + AUTHENTICATION_URL, + token, + data, + (status, responseText) => { + statusCode(JSON.parse(responseText), status, name); + }, + ); }; /* Status codes for linking of repo */ @@ -145,34 +141,29 @@ const linkStatusCode = (status, name) => { const linkRepo = (token, name) => { const AUTHENTICATION_URL = `https://api.github.com/repos/${name}`; - const xhr = new XMLHttpRequest(); - xhr.addEventListener('readystatechange', function () { - if (xhr.readyState === 4) { - const res = JSON.parse(xhr.responseText); - const bool = linkStatusCode(xhr.status, name); - if (xhr.status === 200) { - // BUG FIX + githubRequest( + 'GET', + AUTHENTICATION_URL, + token, + null, + (status, responseText) => { + const res = JSON.parse(responseText); + const bool = linkStatusCode(status, name); + if (status === 200) { if (!bool) { - // unable to gain access to repo in commit mode. Must switch to hook mode. - /* Set mode type to hook */ chrome.storage.local.set({ mode_type: 'hook' }, () => { console.log(`Error linking ${name} to LeetHub`); }); - /* Set Repo Hook to NONE */ chrome.storage.local.set({ leethub_hook: null }, () => { console.log('Defaulted repo hook to NONE'); }); - - /* Hide accordingly */ - document.getElementById('hook_mode').style.display = - 'inherit'; - document.getElementById('commit_mode').style.display = - 'none'; + setDisplayMode('hook'); } else { - /* Change mode type to commit */ - /* Save repo url to chrome storage */ chrome.storage.local.set( - { mode_type: 'commit', repo: res.html_url }, + { + mode_type: 'commit', + repo: res.html_url, + }, () => { $('#error').hide(); $('#success').html( @@ -182,51 +173,30 @@ const linkRepo = (token, name) => { $('#unlink').show(); }, ); - /* Set Repo Hook */ chrome.storage.local.set( { leethub_hook: res.full_name }, () => { console.log('Successfully set new repo hook'); - /* Get problems solved count */ chrome.storage.local.get('stats', (psolved) => { - const { stats } = psolved; - if (stats && stats.solved) { - $('#p_solved').text(stats.solved); - $('#p_solved_easy').text(stats.easy); - $('#p_solved_medium').text(stats.medium); - $('#p_solved_hard').text(stats.hard); - } + displayStats(psolved.stats); }); }, ); - /* Hide accordingly */ - document.getElementById('hook_mode').style.display = 'none'; - document.getElementById('commit_mode').style.display = - 'inherit'; + setDisplayMode('commit'); } } - } - }); - - xhr.open('GET', AUTHENTICATION_URL, true); - xhr.setRequestHeader('Authorization', `token ${token}`); - xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json'); - xhr.send(); + }, + ); }; const unlinkRepo = () => { - /* Set mode type to hook */ chrome.storage.local.set({ mode_type: 'hook' }, () => { console.log(`Unlinking repo`); }); - /* Set Repo Hook to NONE */ chrome.storage.local.set({ leethub_hook: null }, () => { console.log('Defaulted repo hook to NONE'); }); - - /* Hide accordingly */ - document.getElementById('hook_mode').style.display = 'inherit'; - document.getElementById('commit_mode').style.display = 'none'; + setDisplayMode('hook'); }; /* Check for value of select tag, Get Started disabled by default */ @@ -318,10 +288,7 @@ chrome.storage.local.get('mode_type', (data) => { ); $('#error').show(); $('#success').hide(); - /* Hide accordingly */ - document.getElementById('hook_mode').style.display = - 'inherit'; - document.getElementById('commit_mode').style.display = 'none'; + setDisplayMode('hook'); } else { /* Get access to repo */ chrome.storage.local.get('leethub_hook', (repoName) => { @@ -333,11 +300,7 @@ chrome.storage.local.get('mode_type', (data) => { ); $('#error').show(); $('#success').hide(); - /* Hide accordingly */ - document.getElementById('hook_mode').style.display = - 'inherit'; - document.getElementById('commit_mode').style.display = - 'none'; + setDisplayMode('hook'); } else { /* Username exists, at least in storage. Confirm this */ linkRepo(token, hook); @@ -346,10 +309,8 @@ chrome.storage.local.get('mode_type', (data) => { } }); - document.getElementById('hook_mode').style.display = 'none'; - document.getElementById('commit_mode').style.display = 'inherit'; + setDisplayMode('commit'); } else { - document.getElementById('hook_mode').style.display = 'inherit'; - document.getElementById('commit_mode').style.display = 'none'; + setDisplayMode('hook'); } }); diff --git a/welcome.html b/welcome.html index 716ec27e..19825ccc 100644 --- a/welcome.html +++ b/welcome.html @@ -141,6 +141,7 @@ +