Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions backend/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from supabase_service import (
ban_user,
clear_all_staged,
clear_github_token,
count_stats,
get_all_users,
get_pending_files,
Expand Down Expand Up @@ -1130,13 +1131,23 @@ async def commit_now_callback(update: Update, context: ContextTypes.DEFAULT_TYPE
return WAITING_PROTECTED_BRANCH_NAME

else:
error_msg = result.get('message', 'Unknown error')
await channel_logger.log_commit_failed(telegram_id, active_repo, error_msg)
await query.edit_message_text(
f"[X] *Commit failed.*\n\n"
f"Error: {error_msg}\n\n"
f"Your staged files are safe. Try /files again."
)
if result.get("error") == "invalid_token":
clear_github_token(telegram_id)
await channel_logger.log_commit_failed(telegram_id, active_repo, "invalid_token")
await query.edit_message_text(
"πŸ”‘ *Your GitHub token has expired or been revoked.*\n\n"
"Your staged files are safe β€” no changes were made.\n\n"
"Please run /auth to reconnect your GitHub account and try again.",
parse_mode=ParseMode.MARKDOWN
)
else:
error_msg = result.get('message', 'Unknown error')
await channel_logger.log_commit_failed(telegram_id, active_repo, error_msg)
await query.edit_message_text(
f"[X] *Commit failed.*\n\n"
f"Error: {error_msg}\n\n"
f"Your staged files are safe. Try /files again."
)

context.user_data.clear()
return ConversationHandler.END
Expand Down Expand Up @@ -1211,9 +1222,19 @@ async def commit_force_callback(update: Update, context: ContextTypes.DEFAULT_TY
parse_mode=ParseMode.MARKDOWN
)
else:
error_msg = result.get('message', 'Unknown error')
await channel_logger.log_commit_failed(telegram_id, active_repo, error_msg)
await query.edit_message_text(f"[X] Force commit failed: {error_msg}")
if result.get("error") == "invalid_token":
clear_github_token(telegram_id)
await channel_logger.log_commit_failed(telegram_id, active_repo, "invalid_token")
await query.edit_message_text(
"πŸ”‘ *Your GitHub token has expired or been revoked.*\n\n"
"Your staged files are safe β€” no changes were made.\n\n"
"Please run /auth to reconnect your GitHub account and try again.",
parse_mode=ParseMode.MARKDOWN
)
else:
error_msg = result.get('message', 'Unknown error')
await channel_logger.log_commit_failed(telegram_id, active_repo, error_msg)
await query.edit_message_text(f"[X] Force commit failed: {error_msg}")

context.user_data.clear()
return ConversationHandler.END
Expand Down
2 changes: 2 additions & 0 deletions backend/github_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ def commit_files(
}

except GithubException as e:
if e.status == 401:
return {"ok": False, "error": "invalid_token", "message": "GitHub token is invalid or expired. Please re-authenticate via /auth."}
if e.status == 409:
return {"ok": False, "error": "conflict", "message": "SHA conflict on GitHub"}
if e.status == 422:
Expand Down
5 changes: 5 additions & 0 deletions backend/routes/staged_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ async def commit_direct(payload: DirectCommitPayload, telegram_id: str = Depends
status_code=409,
detail=f"Conflict in: {', '.join(conflict_files)}. Use /files in Telegram \u2192 Force Commit.",
)
if result.get("error") == "invalid_token":
raise HTTPException(
status_code=401,
detail="GitHub token is invalid or expired. Please re-authenticate via /auth in Telegram.",
)
raise HTTPException(
status_code=500,
detail=result.get("message", "GitHub commit failed."),
Expand Down
40 changes: 40 additions & 0 deletions backend/supabase_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,43 @@ def update_github_token(telegram_id: str, token: str) -> bool:
print(f"[supabase] update_github_token error: {e}")
return False


def clear_github_token(telegram_id: str) -> bool:
"""Clear a stale or revoked GitHub token so the user is prompted to re-authenticate."""
try:
get_client().table("users") \
.update({"github_token": None}) \
.eq("telegram_id", telegram_id) \
.execute()
return True
except Exception as e:
print(f"[supabase] clear_github_token error: {e}")
return False


def update_github_username(telegram_id: str, github_username: str) -> None:
"""Persist the user's GitHub login so webhooks can map assignee -> telegram_id."""
if not github_username:
return
try:
get_client().table("users") \
.update({"github_username": github_username.lower()}) \
.eq("telegram_id", telegram_id) \
.execute()
except Exception as e:
print(f"[supabase] update_github_username error: {e}")


def get_user_by_github_username(github_username: str) -> dict | None:
"""Reverse lookup: GitHub login -> user row. Case-insensitive. None if unmapped."""
if not github_username:
return None
try:
result = get_client().table("users") \
.select("*") \
.ilike("github_username", github_username) \
.execute()
return result.data[0] if result.data else None
except Exception as e:
print(f"[supabase] get_user_by_github_username error: {e}")
return None