diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dbf6b07..0690d44 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,7 +19,6 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
- python-version: "3.13"
python-version: "3.12"
- name: Cache pip dependencies
@@ -60,7 +59,6 @@ jobs:
uses: actions/setup-python@v5
with:
- python-version: "3.13"
python-version: "3.12"
- name: Cache pip dependencies
diff --git a/backend/github_integration.py b/backend/github_integration.py
new file mode 100644
index 0000000..5198eaa
--- /dev/null
+++ b/backend/github_integration.py
@@ -0,0 +1,49 @@
+import base64
+import requests
+
+def push_solution_to_github(title: str, code: str, access_token: str, repo_name: str) -> dict:
+ """
+ Pushes the LeetCode solution code to the user's GitHub repository.
+ """
+ if not access_token or not repo_name:
+ raise ValueError("GitHub credentials missing.")
+
+ # Sanitize title for filename
+ filename = title.replace(" ", "_").replace("/", "-")
+ file_path = f"solutions/{filename}.py"
+
+ url = f"https://api.github.com/repos/{repo_name}/contents/{file_path}"
+
+ headers = {
+ "Authorization": f"token {access_token}",
+ "Accept": "application/vnd.github.v3+json"
+ }
+
+ # Check if file exists to get the SHA (required for updating)
+ sha = None
+ try:
+ response = requests.get(url, headers=headers, timeout=10)
+ if response.status_code == 200:
+ sha = response.json().get("sha")
+ except Exception as e:
+ print(f"Error checking GitHub file: {e}")
+
+ # Create or update the file
+ commit_message = f"Add solution for {title} via LeetLog AI"
+ encoded_content = base64.b64encode(code.encode("utf-8")).decode("utf-8")
+
+ payload = {
+ "message": commit_message,
+ "content": encoded_content
+ }
+ if sha:
+ payload["sha"] = sha
+
+ try:
+ response = requests.put(url, headers=headers, json=payload, timeout=15)
+ if response.status_code in (200, 201):
+ return {"status": "success", "data": response.json()}
+ else:
+ raise Exception(f"GitHub API Error: {response.status_code} - {response.text}")
+ except Exception as e:
+ raise Exception(f"Failed to push to GitHub: {str(e)}")
diff --git a/backend/main.py b/backend/main.py
index 6156417..efff8ea 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -37,6 +37,7 @@
from services.reminder_scheduler import start_scheduler
from services.complexity_analyzer import analyze_code
from social import share_to_platforms
+from github_integration import push_solution_to_github
load_dotenv()
@@ -165,6 +166,12 @@ class AuthResponse(BaseModel):
class IntegrationSettings(BaseModel):
linkedin_access_token: str | None = None
linkedin_person_urn: str | None = None
+ twitter_api_key: str | None = None
+ twitter_api_secret: str | None = None
+ twitter_access_token: str | None = None
+ twitter_access_secret: str | None = None
+ github_access_token: str | None = None
+ github_repo_name: str | None = None
devto_api_key: str | None = None
whatsapp_number: str | None = None
timezone: str = "Asia/Kolkata"
@@ -291,6 +298,16 @@ def _connected(settings_doc: dict[str, Any]) -> dict[str, bool]:
settings_doc.get("linkedin_access_token")
and settings_doc.get("linkedin_person_urn")
),
+ "twitter": bool(
+ settings_doc.get("twitter_api_key")
+ and settings_doc.get("twitter_api_secret")
+ and settings_doc.get("twitter_access_token")
+ and settings_doc.get("twitter_access_secret")
+ ),
+ "github": bool(
+ settings_doc.get("github_access_token")
+ and settings_doc.get("github_repo_name")
+ ),
"whatsapp": bool(settings_doc.get("whatsapp_number")),
"ai_provider": bool(
settings_doc.get("gemini_api_key")
@@ -534,6 +551,20 @@ async def create_blog(
)
except Exception as e:
print(f"Social sharing failed: {e}")
+
+ # GitHub automatic commit integration
+ if successful and user_settings.get("github_access_token") and user_settings.get("github_repo_name"):
+ try:
+ await run_in_threadpool(
+ push_solution_to_github,
+ problem.title,
+ problem.code,
+ user_settings["github_access_token"],
+ user_settings["github_repo_name"]
+ )
+ except Exception as e:
+ print(f"GitHub push failed: {e}")
+
return {
"status": overall_status,
"data": {
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index aa79d7b..76076c4 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -8,6 +8,12 @@ const TOKEN_KEY = "leetlog_dashboard_token";
const defaultSettings = {
linkedin_access_token: "",
linkedin_person_urn: "",
+ twitter_api_key: "",
+ twitter_api_secret: "",
+ twitter_access_token: "",
+ twitter_access_secret: "",
+ github_access_token: "",
+ github_repo_name: "",
devto_api_key: "",
whatsapp_number: "",
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Kolkata",
@@ -26,6 +32,12 @@ function normalizeSettings(settings) {
...settings,
linkedin_access_token: settings?.linkedin_access_token || "",
linkedin_person_urn: settings?.linkedin_person_urn || "",
+ twitter_api_key: settings?.twitter_api_key || "",
+ twitter_api_secret: settings?.twitter_api_secret || "",
+ twitter_access_token: settings?.twitter_access_token || "",
+ twitter_access_secret: settings?.twitter_access_secret || "",
+ github_access_token: settings?.github_access_token || "",
+ github_repo_name: settings?.github_repo_name || "",
devto_api_key: settings?.devto_api_key || "",
whatsapp_number: settings?.whatsapp_number || "",
gemini_api_key: settings?.gemini_api_key || "",
@@ -72,6 +84,8 @@ function App() {
connected.ai_provider,
connected.devto,
connected.linkedin,
+ connected.twitter,
+ connected.github,
connected.whatsapp
];
return Math.round((checks.filter(Boolean).length / checks.length) * 100);
@@ -129,6 +143,12 @@ function App() {
...settings,
linkedin_access_token: settings.linkedin_access_token || null,
linkedin_person_urn: settings.linkedin_person_urn || null,
+ twitter_api_key: settings.twitter_api_key || null,
+ twitter_api_secret: settings.twitter_api_secret || null,
+ twitter_access_token: settings.twitter_access_token || null,
+ twitter_access_secret: settings.twitter_access_secret || null,
+ github_access_token: settings.github_access_token || null,
+ github_repo_name: settings.github_repo_name || null,
devto_api_key: settings.devto_api_key || null,
whatsapp_number: settings.whatsapp_number || null,
gemini_api_key: settings.gemini_api_key || null,
@@ -393,6 +413,36 @@ setAnalysisResult(data);
+
+
+
+
+
+
+
+
+
+
+
+