From c6e8c87ca00d85dd4a809f768afd568cd4fb2977 Mon Sep 17 00:00:00 2001 From: Aly Ghallab <90642388+AlyHG@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:04:31 -0400 Subject: [PATCH 1/4] Update action.js to handle locked LeetCode Premium Problems Added error handling in the `getInfo` function to skip locked problems. When the function encounters a locked problem (HTTP 403 error), it logs a message and skips the problem instead of retrying or throwing an exception. - Updated the `getQuestionData` function to handle locked problems. If fetching the question data results in a locked problem error (HTTP 403), it logs the error and returns null to indicate that the problem should be skipped. Modified the `sync` function to skip submissions related to locked problems. It continues the sync process for other problems, ensuring that locked problems do not cause the entire sync process to fail. --- src/action.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/action.js b/src/action.js index 9f7589bb..60394449 100644 --- a/src/action.js +++ b/src/action.js @@ -104,7 +104,12 @@ async function getInfo(submission, session, csrfToken) { code: response.data.data.submissionDetails.code, }; } catch (exception) { - if (retryCount >= maxRetries) { + if (retryCount >= maxRetries) { + // If problem is locked due to user not having LeetCode Premium + if (exception.response && exception.response.status === 403) { + log(`Skipping locked problem: ${submission.title}`); + return null; + } throw exception; } log( @@ -235,6 +240,11 @@ async function getQuestionData(titleSlug, leetcodeSession, csrfToken) { const result = await response.data; return result.data.question.content; } catch (error) { + // If problem is locked due to user not having LeetCode Premium + if (error.response && error.response.status === 403) { + log(`Skipping locked problem: ${titleSlug}`); + return null; + } console.log("error", error); } } @@ -415,6 +425,11 @@ async function sync(inputs) { leetcodeSession, leetcodeCSRFToken, ); + if (!submission) { + // Skip this submission if it is null (locked problem) + continue; + } + // Get the question data for the submission. const questionData = await getQuestionData( @@ -422,6 +437,10 @@ async function sync(inputs) { leetcodeSession, leetcodeCSRFToken, ); + if (questionData === null) { + // Skip this submission if question data is null (locked problem) + continue; + } [treeSHA, latestCommitSHA] = await commit({ octokit, owner, From 84b5eb11b60967139adfb2d968037dfbdccdeec3 Mon Sep 17 00:00:00 2001 From: Aly Ghallab <90642388+AlyHG@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:59:00 -0400 Subject: [PATCH 2/4] Updated the .yml workflow in the README.md to use my forked version of the leetcode-sync GitHub Action --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 929bfab1..c1d7457a 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ GitHub Action for automatically syncing LeetCode submissions to a GitHub reposit steps: - name: Sync - uses: joshcai/leetcode-sync@v1.6 + uses: AlyHG/leetcode-sync@master with: github-token: ${{ github.token }} leetcode-csrf-token: ${{ secrets.LEETCODE_CSRF_TOKEN }} From b3271cd14d958bdf18adb9c41107b2853046cb08 Mon Sep 17 00:00:00 2001 From: Aly Ghallab <90642388+AlyHG@users.noreply.github.com> Date: Wed, 19 Jun 2024 12:05:36 -0400 Subject: [PATCH 3/4] Update README.md --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index c1d7457a..27d65c5c 100644 --- a/README.md +++ b/README.md @@ -111,3 +111,17 @@ Special thanks to the following people who helped beta test this GitHub Action a - [uakfdotb](https://github.com/uakfdotb) - [hexecute](https://github.com/hexecute) - [JonathanZhu11](https://github.com/JonathanZhu11) + +## Updated by [Aly Ghallab](https://github.com/AlyHG) to Handle Locked LeetCode Premium Problems and Improve Sync Reliability - June 19, 2024 + +- **Error Handling for Locked Problems:** Added error handling in the `getInfo` function to skip locked problems. When the function encounters a locked problem (HTTP 403 error), it logs a message and skips the problem instead of retrying or throwing an exception. +- **Fetching Question Data:** Updated the `getQuestionData` function to handle errors when fetching question data for locked problems. If fetching the question data results in a locked problem error (HTTP 403), it logs the error and returns null to indicate that the problem should be skipped. +- **Sync Function Modification:** Modified the `sync` function to continue syncing other problems even if some are locked, ensuring that locked problems do not cause the entire sync process to fail. +- **Additional Logging:** Added logging to help identify and skip locked problems during the sync process. + + +These changes improve the sync process by handling scenarios where some LeetCode problems are locked, allowing the action to continue syncing all available, unlocked problems successfully. + + + + From 4303d027d5007060e17ddac28a0cd25208c98abc Mon Sep 17 00:00:00 2001 From: Aly Ghallab Date: Mon, 24 Jun 2024 10:39:54 -0400 Subject: [PATCH 4/4] Rewrote condition for syntax consistency and reverted README changes for merge - Changed condition to "submission === null" in src/action.js for syntax consistency. - Reverted "uses" line in README.md to point back to joshcai/leetcode-sync@v1.6. - Removed self-crediting section from README.md. Agreed to include this information in the release notes instead. --- README.md | 19 +++---------------- src/action.js | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 27d65c5c..19755e2f 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,14 @@ GitHub Action for automatically syncing LeetCode submissions to a GitHub reposit steps: - name: Sync - uses: AlyHG/leetcode-sync@master + uses: joshcai/leetcode-sync@v1.6 with: github-token: ${{ github.token }} leetcode-csrf-token: ${{ secrets.LEETCODE_CSRF_TOKEN }} leetcode-session: ${{ secrets.LEETCODE_SESSION }} destination-folder: my-folder verbose: true - commit-header: '[LeetCode Sync]' + commit-header: "[LeetCode Sync]" ``` 6. After you've submitted a LeetCode solution, run the workflow by going to the `Actions` tab, clicking the action name, e.g. `Sync Leetcode`, and then clicking `Run workflow`. The workflow will also automatically run once a week by default (can be configured via the `cron` parameter). @@ -101,6 +101,7 @@ Since this file is in the `.gitignore` file to avoid users accidentally committi This likely means that you hit a rate limit when committing to GitHub (this may happen if you have over ~300 submissions initially). Since the syncer writes in reverse chronological order, it should pick up syncing submissions from where it left off on the next run of the workflow, so just retry the workflow manually after some time. #### Job fails with "HttpError: Resource not accessible by integration" + This means the github token you're using does not have permission to write to your repo. If you're using the default `github.token` method follow the instructions [here] (https://docs.github.com/en/actions/security-guides/automatic-token-authentication) ## Acknowledgements @@ -111,17 +112,3 @@ Special thanks to the following people who helped beta test this GitHub Action a - [uakfdotb](https://github.com/uakfdotb) - [hexecute](https://github.com/hexecute) - [JonathanZhu11](https://github.com/JonathanZhu11) - -## Updated by [Aly Ghallab](https://github.com/AlyHG) to Handle Locked LeetCode Premium Problems and Improve Sync Reliability - June 19, 2024 - -- **Error Handling for Locked Problems:** Added error handling in the `getInfo` function to skip locked problems. When the function encounters a locked problem (HTTP 403 error), it logs a message and skips the problem instead of retrying or throwing an exception. -- **Fetching Question Data:** Updated the `getQuestionData` function to handle errors when fetching question data for locked problems. If fetching the question data results in a locked problem error (HTTP 403), it logs the error and returns null to indicate that the problem should be skipped. -- **Sync Function Modification:** Modified the `sync` function to continue syncing other problems even if some are locked, ensuring that locked problems do not cause the entire sync process to fail. -- **Additional Logging:** Added logging to help identify and skip locked problems during the sync process. - - -These changes improve the sync process by handling scenarios where some LeetCode problems are locked, allowing the action to continue syncing all available, unlocked problems successfully. - - - - diff --git a/src/action.js b/src/action.js index 60394449..babad2ad 100644 --- a/src/action.js +++ b/src/action.js @@ -87,13 +87,13 @@ async function getInfo(submission, session, csrfToken) { headers, }); const runtimePercentile = `${response.data.data.submissionDetails.runtimePercentile.toFixed( - 2, + 2 )}%`; const memoryPercentile = `${response.data.data.submissionDetails.memoryPercentile.toFixed( - 2, + 2 )}%`; const questionId = pad( - response.data.data.submissionDetails.question.questionId.toString(), + response.data.data.submissionDetails.question.questionId.toString() ); log(`Got info for submission #${submission.id}`); @@ -104,18 +104,18 @@ async function getInfo(submission, session, csrfToken) { code: response.data.data.submissionDetails.code, }; } catch (exception) { - if (retryCount >= maxRetries) { + if (retryCount >= maxRetries) { // If problem is locked due to user not having LeetCode Premium if (exception.response && exception.response.status === 403) { log(`Skipping locked problem: ${submission.title}`); - return null; + return null; } throw exception; } log( "Error fetching submission info, retrying in " + 3 ** retryCount + - " seconds...", + " seconds..." ); await delay(3 ** retryCount * 1000); return getInfo(maxRetries, retryCount + 1); @@ -235,7 +235,7 @@ async function getQuestionData(titleSlug, leetcodeSession, csrfToken) { const response = await axios.post( "https://leetcode.com/graphql/", graphql, - { headers }, + { headers } ); const result = await response.data; return result.data.question.content; @@ -243,7 +243,7 @@ async function getQuestionData(titleSlug, leetcodeSession, csrfToken) { // If problem is locked due to user not having LeetCode Premium if (error.response && error.response.status === 403) { log(`Skipping locked problem: ${titleSlug}`); - return null; + return null; } console.log("error", error); } @@ -317,7 +317,7 @@ async function sync(inputs) { for (const commit of commits.data) { if ( !commit.commit.message.startsWith( - !!commitHeader ? commitHeader : COMMIT_MESSAGE, + !!commitHeader ? commitHeader : COMMIT_MESSAGE ) ) { continue; @@ -365,7 +365,7 @@ async function sync(inputs) { const response = await axios.post( "https://leetcode.com/graphql/", graphql, - { headers }, + { headers } ); log(`Successfully fetched submission from LeetCode, offset ${offset}`); return response; @@ -376,7 +376,7 @@ async function sync(inputs) { log( "Error fetching submissions, retrying in " + 3 ** retryCount + - " seconds...", + " seconds..." ); // There's a rate limit on LeetCode API, so wait with backoff before retrying. await delay(3 ** retryCount * 1000); @@ -423,19 +423,19 @@ async function sync(inputs) { submission = await getInfo( submissions[i], leetcodeSession, - leetcodeCSRFToken, + leetcodeCSRFToken ); - if (!submission) { + + if (submission === null) { // Skip this submission if it is null (locked problem) continue; } - // Get the question data for the submission. const questionData = await getQuestionData( submission.titleSlug, leetcodeSession, - leetcodeCSRFToken, + leetcodeCSRFToken ); if (questionData === null) { // Skip this submission if question data is null (locked problem)