This personal Telegram bot rewards Accepted LeetCode submissions from _mitraboga. It verifies the problem's difficulty and creates a fixed number of commits in the configured GitHub repository.
| Problem difficulty | Commits per problem |
|---|---|
| Easy | 10 |
| Medium | 20 |
| Hard | 50 |
The CS question bank remains available as optional practice. /forcecommit remains a manual fallback.
- Solve any LeetCode problem and receive Accepted. The daily challenge is a suggestion; any problem qualifies.
- Send
/checkin Telegram, or wait for an automatic check. - The bot retrieves the profile's recent Accepted submissions and verifies difficulty.
- Each problem gets one reward after activation, identified by username and problem slug. Repeated submissions of that problem do not earn more commits.
- The bot creates 10, 20, or 50 JSON records, one per commit, on the destination repository's default branch.
Each record contains the problem title/link, submission ID/link, acceptance time, local date, difficulty, reward size, and reward step. These are reward log commits, not automatically uploaded solution code.
Rewards live at leetcode/_mitraboga/<problem-slug>/001.json through 010.json, 020.json, or 050.json. The first record establishes the canonical reward. The last record confirms completion. If a request fails after 7 of 50 commits, /check resumes the unfinished reward and creates the remaining 43. Deterministic file paths prevent duplicate rewards across /check, restarts, GitHub Actions, and lost API responses.
The default activation date is 2026-10-07 in Asia/Kolkata. Earlier submissions do not earn rewards. Set LEETCODE_START_DATE once and keep it fixed in both hosting and Actions. Solving an older problem again after activation can earn its first recorded reward; the public recent-submission list cannot establish your full lifetime solve history.
| Command | Behavior |
|---|---|
/start, /help |
Help and reward rules |
/daily |
Today's LeetCode challenge |
/check |
Discover accepted problems and retry pending rewards |
/status |
Linked profile, activation date, and reward settings |
/forcecommit [n] [tag] |
Manual override; default 1, maximum 50 commits |
/diagnose |
Read-only GitHub authentication check; no token values displayed |
/notify HH:MM [Area/City] |
Schedule a daily LeetCode reminder |
/when, /unnotify |
Show or disable the saved reminder |
/csquiz, /quiz |
Optional five-question CS practice; no reward commits |
/score |
Practice accuracy, including existing historical scores |
/streak |
Streak and solve totals from locally synced reward records |
/whoami |
Show Telegram user/chat IDs for setup |
Examples:
/daily
/check
/forcecommit 10 busy-day
/notify 09:00 Asia/Kolkata
/csquiz
The obsolete contribution-count /quiz flow has been replaced by CS practice. Answers are consumed once, answered buttons are removed, old message callbacks cannot affect new questions, and questions rotate without repeats until the bank is exhausted within a running session. Only the configured owner can use reward commands, and only in a private chat.
Python 3.11 or newer is required. Get a bot token from BotFather.
git clone https://github.com/mitraboga/ContributionGraphPopQuiz.git
cd ContributionGraphPopQuiz
python -m venv .venvWindows PowerShell:
.\.venv\Scripts\Activate.ps1
Copy-Item .env.example .env
pip install -r requirements.txtmacOS/Linux:
source .venv/bin/activate
cp .env.example .env
pip install -r requirements.txtFill in .env. Real secrets are excluded from Git and Docker builds:
BOT_TOKEN=YOUR_BOTFATHER_TOKEN
TELEGRAM_USER_ID=YOUR_NUMERIC_USER_ID
TELEGRAM_CHAT_ID=YOUR_PRIVATE_CHAT_ID
LEETCODE_USERNAME=_mitraboga
LEETCODE_START_DATE=2026-10-07
TZ=Asia/Kolkata
GITHUB_TOKEN=YOUR_PERSONAL_ACCESS_TOKEN
GITHUB_REPO=mitraboga/YOUR_EXISTING_COMMIT_REPOSITORY
GH_USER_NAME=Mitra Boga
GH_USER_EMAIL=YOUR_VERIFIED_GITHUB_EMAIL
DB_PATH=quiz_scores.dbRun:
python main.pyUse /whoami to obtain your numeric IDs if needed, then update the environment and restart. In a private chat the user and chat IDs normally match. TELEGRAM_CHAT_ID can also supply owner identity when TELEGRAM_USER_ID is unset.
Create a fine-grained personal access token for the destination repository with Contents: Read and write. Use a verified GitHub email (or your GitHub-provided noreply address). GH_USER_NAME and GH_USER_EMAIL are optional as a pair; leave both empty to let GitHub attribute the commits to the token owner. A repository with no default branch needs an initial commit before rewards can be written.
- Merge/deploy the updated code on your Render service.
- In Render → your service → Environment, replace the invalid
GITHUB_TOKENwith a valid token. KeepBOT_TOKENand the existing destinationGITHUB_REPO. - Add
TELEGRAM_USER_ID,TELEGRAM_CHAT_ID,LEETCODE_USERNAME=_mitraboga,LEETCODE_START_DATE=2026-10-07, andTZ=Asia/Kolkata. Keep the same activation date in Actions. - Set a custom
WEBHOOK_SECRETusing letters, digits,_, and-. Existing non-default secrets can be retained. Render'sRENDER_EXTERNAL_URLautomatically selects webhook mode. - Start command:
python main.py. Build command:pip install -r requirements.txt. - Redeploy, then send
/start,/status, and/diagnose. Once authentication succeeds, solve a problem and send/check.
The webhook uses /telegram and verifies Telegram's secret header. The secret is not embedded in URLs. Hosting environment values take precedence over .env, preventing stale local values from overriding the updated token.
The app checks submissions every 15 minutes while running. Render free services can sleep after inactivity and their local files are ephemeral. SQLite reminder preferences, practice scores, pending queues, and locally synced streak history therefore need a persistent disk for durability. Reward deduplication itself survives a lost SQLite database because the records are stored in GitHub. /streak reports the synced cache; after cache loss, /check can repopulate only submissions still visible in LeetCode's recent list.
The included LeetCode reward sync workflow checks at minutes 07 and 37 each hour, even when Render is asleep. Its schedule is opt-in and runs from the default branch. Configure this repository under Settings → Secrets and variables → Actions:
Secrets
| Name | Value |
|---|---|
COMMIT_GITHUB_TOKEN |
Valid personal token with write access to the destination repository |
BOT_TOKEN |
Existing Telegram bot token, for completion/error notifications |
TELEGRAM_CHAT_ID |
Your private chat ID |
Variables
| Name | Value |
|---|---|
GITHUB_REPO |
Your existing destination repository, owner/name |
LEETCODE_USERNAME |
_mitraboga |
LEETCODE_START_DATE |
2026-10-07 |
GH_USER_NAME, GH_USER_EMAIL |
Both set, or both unset, matching Render |
LEETCODE_SYNC_ENABLED |
true to enable scheduled rewards |
LEETCODE_REMINDER_ENABLED |
Optional true for a 09:00 IST reminder from Actions |
The Actions token secret is named COMMIT_GITHUB_TOKEN to distinguish it from GitHub's built-in workflow token. Use your personal token so commits are attributed to your account. The same destination and author settings must be used by Render and Actions.
After merging, run Actions → LeetCode reward sync → Run workflow to verify configuration. Leave LEETCODE_REMINDER_ENABLED unset if using /notify to avoid two daily reminders. Scheduled Actions can be delayed under load; /check remains available. See GitHub's schedule guidance.
GitHub 401: The deployed token is invalid, expired, revoked, or incorrectly copied. Update Render Environment → GITHUB_TOKEN and Actions secrets → COMMIT_GITHUB_TOKEN, then redeploy. Updating code or /setuser cannot repair an invalid token. Never paste credentials into Telegram or commit them.
GitHub 403/429: Check Contents permission and repository access. If rate limited, wait before /check. Commits are serialized with a delay between writes. Pending reward steps remain retryable.
GitHub 404: Check GITHUB_REPO, token repository access, and the default branch. /diagnose checks authentication/read access without making a test commit; write permission is exercised by an actual reward or manual override.
No new reward: Confirm the profile, Accepted status, activation date, and whether that problem was already rewarded. LeetCode exposes only recent Accepted submissions (requested limit: 20), so long outages or more than 20 submissions between checks can hide unsynced solves. The website GraphQL interface is unofficial and can change or become unavailable; the bot reports errors instead of guessing completion or difficulty.
Commits missing from the graph: Commits must satisfy GitHub's contribution requirements, including account-linked author email and an eligible repository/default branch. Private contributions also depend on profile visibility settings. The graph can take time to update. Reward records preserve the acceptance day, but commits appear on the day they are actually created; late retries do not backdate Git history.
Manual override interrupted: The response states how many commits completed. /forcecommit creates a new manual request every time; choose only the remaining count if you intend to complete the same total. It does not mark LeetCode problems solved or extend their streak.
pip install pytest
python -m pytest -q
python -m compileall -q main.py rewards.py github_committer.py leetcode_client.py
# Read-only GitHub configuration check; creates no commits:
python github_committer.pymain.py handles Telegram commands and schedules; leetcode_client.py reads public metadata; rewards.py queues and syncs rewards; github_committer.py creates resumable GitHub records; storage.py retains existing SQLite tables; questions.py holds the optional CS bank. sync_leetcode.py and send_daily.py provide standalone Actions entry points. Tests use in-memory GitHub fixtures, never live reward writes.