Repository navigation
Implement Telegram bot for product sales and balance - #60
unnjjj300-arch wants to merge 1 commit into
Conversation
Added a Telegram bot implementation with user balance management and product purchasing functionality.
📝 WalkthroughWalkthroughA ChangesTelegram Bot Purchase & Admin Approval Flow
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Warning |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@railway.toml`:
- Line 36: The PAYMENT_METHOD variable on line 36 contains sensitive personal
and financial account information that should not be stored in source code.
Remove the hardcoded payment details from this line and also check lines 70-71
which duplicate this information. Instead, store the payment account details in
deployment configuration (such as environment variables or secrets management)
and reference the configuration variable in the railway.toml file. This ensures
sensitive PII is not exposed in the repository and maintains a single source of
truth for payment instructions to prevent drift.
- Around line 164-169: The issue is that process_admin_otp sends the OTP to the
user before deducting their balance, creating a window where the user could
receive the product without payment if the admin's manual "Cut Balance & Finish"
action is missed or fails. Move the balance deduction or reservation logic to
execute before sending the OTP message (before the bot.send_message call with
the OTP text), ensuring the user's funds are atomically debited or reserved
before they receive the OTP and can access the product.
- Around line 100-102: The balance top-up callbacks (add_150_, add_250_,
rej_bal_) currently credit the user's balance every time the callback is
processed, making them non-idempotent and vulnerable to duplicate credits if
clicked multiple times. Add a unique request/top-up ID to the callback_data
along with the user_id (for example, include a request_id parameter in the
callback_data string), then in the callback handlers for these add_* and
rej_bal_ operations, query a persisted request tracking table before mutating
user_balances to verify the request status is still pending, and atomically
update that request's status to approved or rejected immediately after
processing to prevent reprocessing, rather than relying only on message caption
edits.
- Around line 171-177: The code imports the Flask module, but Flask is not
listed as a dependency in the project's pyproject.toml file, which will cause an
import failure at runtime. Add flask as a project dependency in the dependencies
section of pyproject.toml to ensure it is available when the Flask import
statement is executed.
- Around line 14-25: The load_balances function uses a bare except clause that
silently returns an empty dictionary when the balance file is corrupted or
unreadable, which can lead to permanent loss of user balances if save_balances
is called afterward. Replace the bare except with specific exception handling
that logs the actual error and re-raises it to fail loudly rather than silently
resetting the ledger. Additionally, modify save_balances to use atomic file
writing (write to a temporary file first, then rename it) to ensure that a
partial write does not corrupt the user funds data in the actual balance file.
- Around line 108-146: The handle_all_callbacks function processes sensitive
operations like balance additions, rejections, and OTP sending without verifying
that the user performing the action is the admin. Add an authorization check
comparing call.from_user.id against ADMIN_CHAT_ID at the beginning of the
function or before processing any admin-level actions (the "add", "rej",
"admin_*", and "user_reqotp" cases). If the user is not authorized, reject the
callback request with an appropriate error message instead of proceeding with
the operation.
- Around line 8-10: The Telegram bot token and admin chat ID are hardcoded
directly in the source code, which is a security risk. Remove the hardcoded
string values for API_TOKEN and ADMIN_CHAT_ID, and instead load both from
environment variables using appropriate environment variable retrieval methods
(such as os.getenv or similar). Ensure the bot initialization with
telebot.TeleBot references the token retrieved from the environment variable
rather than a hardcoded string.
- Around line 82-90: The code overwrites existing pending orders in
current_deals[user_id] when a user selects multiple products, causing admin
buttons to operate on the wrong product. Add a check before creating a new entry
in current_deals to prevent overwriting if a deal is already pending for that
user_id, or implement a unique deal_id system by replacing user_id with a unique
identifier in the callback_data parameter of the admin_sendnum callback and
storing deals with that unique deal_id as the key instead of just user_id.
Ensure the admin button callbacks reference the correct product and price by
maintaining proper deal tracking throughout the transaction lifecycle.
- Around line 2-3: The railway.toml file contains Python code starting with the
import telebot statement on line 3, which breaks TOML parsing. Remove all Python
code (from the import telebot line through the end of the telebot
implementation) from railway.toml and move it into main.py or a separate Python
module. Keep railway.toml containing only the startCommand configuration that
references the entry point (main.py), allowing the deployment configuration file
to remain valid TOML.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| startCommand = "uv run python main.py" | ||
| import telebot |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify that railway.toml is valid TOML.
# Expected result today: TOMLDecodeError near the first Python line.
python - <<'PY'
import pathlib
import tomllib
path = pathlib.Path("railway.toml")
tomllib.loads(path.read_text(encoding="utf-8"))
print("railway.toml parses successfully")
PYRepository: aeither/telegram-bot-python
Length of output: 799
Move Python code out of railway.toml—the file cannot parse as TOML.
Line 3 begins Python code (import telebot) inside the TOML config, causing a parse error at line 3, column 8. Since startCommand on line 2 runs main.py (not the embedded bot code), move lines 3–183 into main.py or a separate Python module and keep railway.toml as deployment config only.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 2 - 3, The railway.toml file contains Python code
starting with the import telebot statement on line 3, which breaks TOML parsing.
Remove all Python code (from the import telebot line through the end of the
telebot implementation) from railway.toml and move it into main.py or a separate
Python module. Keep railway.toml containing only the startCommand configuration
that references the entry point (main.py), allowing the deployment configuration
file to remain valid TOML.
| API_TOKEN = '8960267703:AAFdc1t16LXQibSMS82-qy4jAzwnPQuYatM' | ||
| bot = telebot.TeleBot(API_TOKEN) | ||
| ADMIN_CHAT_ID = 7457612833 |
There was a problem hiding this comment.
Revoke the committed bot token and load secrets from the environment.
The Telegram bot token is hardcoded in source. Treat it as compromised, rotate it with BotFather, and use environment variables for both the token and deployment-specific admin ID.
🔐 Proposed fix
-API_TOKEN = '<hardcoded bot token>'
-bot = telebot.TeleBot(API_TOKEN)
-ADMIN_CHAT_ID = 7457612833
+API_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
+bot = telebot.TeleBot(API_TOKEN)
+ADMIN_CHAT_ID = int(os.environ["ADMIN_CHAT_ID"])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 8 - 10, The Telegram bot token and admin chat ID
are hardcoded directly in the source code, which is a security risk. Remove the
hardcoded string values for API_TOKEN and ADMIN_CHAT_ID, and instead load both
from environment variables using appropriate environment variable retrieval
methods (such as os.getenv or similar). Ensure the bot initialization with
telebot.TeleBot references the token retrieved from the environment variable
rather than a hardcoded string.
| def load_balances(): | ||
| if os.path.exists(BALANCES_FILE): | ||
| try: | ||
| with open(BALANCES_FILE, "r") as f: | ||
| return {int(k): v for k, v in json.load(f).items()} | ||
| except: | ||
| return {} | ||
| return {} | ||
|
|
||
| def save_balances(): | ||
| with open(BALANCES_FILE, "w") as f: | ||
| json.dump(user_balances, f) |
There was a problem hiding this comment.
Do not silently reset the balance ledger on load errors.
The bare except returns an empty ledger for corrupted/unreadable JSON; the next save_balances() can permanently overwrite real balances. Fail loudly and write atomically so a partial write does not corrupt user funds.
💾 Proposed fix
def load_balances():
if os.path.exists(BALANCES_FILE):
try:
- with open(BALANCES_FILE, "r") as f:
+ with open(BALANCES_FILE, "r", encoding="utf-8") as f:
return {int(k): v for k, v in json.load(f).items()}
- except:
- return {}
+ except (OSError, ValueError, json.JSONDecodeError) as exc:
+ raise RuntimeError(f"Unable to load {BALANCES_FILE}") from exc
return {}
def save_balances():
- with open(BALANCES_FILE, "w") as f:
- json.dump(user_balances, f)
+ tmp_file = f"{BALANCES_FILE}.tmp"
+ with open(tmp_file, "w", encoding="utf-8") as f:
+ json.dump(user_balances, f)
+ os.replace(tmp_file, BALANCES_FILE)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 14 - 25, The load_balances function uses a bare
except clause that silently returns an empty dictionary when the balance file is
corrupted or unreadable, which can lead to permanent loss of user balances if
save_balances is called afterward. Replace the bare except with specific
exception handling that logs the actual error and re-raises it to fail loudly
rather than silently resetting the ledger. Additionally, modify save_balances to
use atomic file writing (write to a temporary file first, then rename it) to
ensure that a partial write does not corrupt the user funds data in the actual
balance file.
| "3": {"name": "Pakistan number", "price": 150} | ||
| } | ||
|
|
||
| PAYMENT_METHOD = "Easypaisa: 03293891772: Muhammad zubair" |
There was a problem hiding this comment.
Move payment account details out of source.
The payment method contains personal/financial account details and Line 71 duplicates part of it. Store this in deployment configuration and render it from one source to avoid leaking PII and drifting payment instructions.
🔐 Proposed fix
-PAYMENT_METHOD = "..."
+PAYMENT_METHOD = os.environ["PAYMENT_METHOD"]- bot.send_message(message.chat.id, f"💰 **Payment Details:**\n\n{PAYMENT_METHOD}\n\n📌 Account Number: 03293891772\n👉 Screenshot send karein.")
+ bot.send_message(message.chat.id, f"💰 **Payment Details:**\n\n{PAYMENT_METHOD}\n\n👉 Screenshot send karein.")Also applies to: 70-71
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` at line 36, The PAYMENT_METHOD variable on line 36 contains
sensitive personal and financial account information that should not be stored
in source code. Remove the hardcoded payment details from this line and also
check lines 70-71 which duplicate this information. Instead, store the payment
account details in deployment configuration (such as environment variables or
secrets management) and reference the configuration variable in the railway.toml
file. This ensures sensitive PII is not exposed in the repository and maintains
a single source of truth for payment instructions to prevent drift.
| if product: | ||
| if user_balances.get(user_id, 0) >= product['price']: | ||
| current_deals[user_id] = {"product_name": product['name'], "price": product['price']} | ||
|
|
||
| markup = types.InlineKeyboardMarkup() | ||
| markup.add(types.InlineKeyboardButton("📤 Send Number", callback_data=f"admin_sendnum_{user_id}")) | ||
|
|
||
| admin_text = f"🔔 **Naya Number Order!**\n👤 User ID: `{user_id}`\n📦 Product: {product['name']}\n💵 Keemat: {product['price']} PKR\n\n👇 Niche button daba kar number dein:" | ||
| bot.send_message(ADMIN_CHAT_ID, admin_text, reply_markup=markup, parse_mode="Markdown") |
There was a problem hiding this comment.
Prevent pending orders from being overwritten.
current_deals[user_id] supports only one pending deal. If the user selects another product before admin finishes the first one, the old admin buttons still target the same user but now operate on the new product/price. Block new orders while one is pending, or use a unique deal_id in every callback.
🧾 Minimal guard
if user_balances.get(user_id, 0) >= product['price']:
+ if user_id in current_deals:
+ bot.answer_callback_query(call.id, "You already have a pending order.", show_alert=True)
+ return
current_deals[user_id] = {"product_name": product['name'], "price": product['price']}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 82 - 90, The code overwrites existing pending
orders in current_deals[user_id] when a user selects multiple products, causing
admin buttons to operate on the wrong product. Add a check before creating a new
entry in current_deals to prevent overwriting if a deal is already pending for
that user_id, or implement a unique deal_id system by replacing user_id with a
unique identifier in the callback_data parameter of the admin_sendnum callback
and storing deals with that unique deal_id as the key instead of just user_id.
Ensure the admin button callbacks reference the correct product and price by
maintaining proper deal tracking throughout the transaction lifecycle.
| markup.add(types.InlineKeyboardButton("✅ Add 150 PKR", callback_data=f"add_150_{user_id}"), | ||
| types.InlineKeyboardButton("✅ Add 250 PKR", callback_data=f"add_250_{user_id}"), | ||
| types.InlineKeyboardButton("❌ Reject", callback_data=f"rej_bal_{user_id}")) |
There was a problem hiding this comment.
Make balance top-ups idempotent.
The add_* callback credits balance every time it is processed. Use a unique top-up/request ID with a persisted processed status before mutating user_balances; editing the caption is not an accounting guard.
🧾 Minimum direction
- markup.add(types.InlineKeyboardButton("✅ Add 150 PKR", callback_data=f"add_150_{user_id}"),
- types.InlineKeyboardButton("✅ Add 250 PKR", callback_data=f"add_250_{user_id}"),
- types.InlineKeyboardButton("❌ Reject", callback_data=f"rej_bal_{user_id}"))
+ topup_id = create_persisted_topup_request(user_id, message.photo[-1].file_id)
+ markup.add(types.InlineKeyboardButton("✅ Add 150 PKR", callback_data=f"add_150_{topup_id}"),
+ types.InlineKeyboardButton("✅ Add 250 PKR", callback_data=f"add_250_{topup_id}"),
+ types.InlineKeyboardButton("❌ Reject", callback_data=f"rej_bal_{topup_id}"))Then process only top-ups whose persisted status is still pending, and atomically mark them approved/rejected before acknowledging the callback.
Also applies to: 113-119, 121-124
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 100 - 102, The balance top-up callbacks (add_150_,
add_250_, rej_bal_) currently credit the user's balance every time the callback
is processed, making them non-idempotent and vulnerable to duplicate credits if
clicked multiple times. Add a unique request/top-up ID to the callback_data
along with the user_id (for example, include a request_id parameter in the
callback_data string), then in the callback handlers for these add_* and
rej_bal_ operations, query a persisted request tracking table before mutating
user_balances to verify the request status is still pending, and atomically
update that request's status to approved or rejected immediately after
processing to prevent reprocessing, rather than relying only on message caption
edits.
| @bot.callback_query_handler(func=lambda call: True) | ||
| def handle_all_callbacks(call): | ||
| data = call.data.split('_') | ||
| action = data[0] | ||
|
|
||
| if action == "add": | ||
| amount, target_user = int(data[1]), int(data[2]) | ||
| if target_user not in user_balances: user_balances[target_user] = 0 | ||
| user_balances[target_user] += amount | ||
| save_balances() | ||
| bot.send_message(target_user, f"🎉 Balance Loaded! Added {amount} PKR. Total: {user_balances[target_user]} PKR.") | ||
| bot.edit_message_caption(f"✅ Added {amount} PKR to {target_user}", chat_id=call.message.chat.id, message_id=call.message.message_id) | ||
|
|
||
| elif action == "rej" and data[1] == "bal": | ||
| target_user = int(data[2]) | ||
| bot.send_message(target_user, "❌ Aapka screenshot reject kar diya gaya hai.") | ||
| bot.edit_message_caption("❌ Screenshot Rejected", chat_id=call.message.chat.id, message_id=call.message.message_id) | ||
|
|
||
| elif action == "admin" and data[1] == "sendnum": | ||
| target_user = data[2] | ||
| msg = bot.send_message(ADMIN_CHAT_ID, f"✍️ Is user `{target_user}` ke liye Number likh kar send karein:") | ||
| bot.register_next_step_handler(msg, process_admin_number, target_user) | ||
| bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.message_id) | ||
|
|
||
| elif action == "user" and data[1] == "reqotp": | ||
| target_user = data[2] | ||
| markup = types.InlineKeyboardMarkup() | ||
| markup.add(types.InlineKeyboardButton("🔑 Send OTP", callback_data=f"admin_sendotp_{target_user}")) | ||
| bot.send_message(ADMIN_CHAT_ID, f"📩 **ALERT!** User `{target_user}` OTP maang raha hai!", reply_markup=markup) | ||
| bot.edit_message_text("⏳ OTP Request Sent to Admin. Waiting...", chat_id=call.message.chat.id, message_id=call.message.message_id) | ||
|
|
||
| elif action == "admin" and data[1] == "sendotp": | ||
| target_user = data[2] | ||
| msg = bot.send_message(ADMIN_CHAT_ID, f"✍️ User `{target_user}` ke liye OTP Code likh kar send karein:") | ||
| bot.register_next_step_handler(msg, process_admin_otp, target_user) | ||
| bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.message_id) | ||
|
|
||
| elif action == "admin" and data[1] == "finish": | ||
| target_user = int(data[2]) |
There was a problem hiding this comment.
Enforce admin authorization inside the callback handler.
The handler processes add, rej, and admin_* actions without checking who pressed the button. Do not rely only on chat routing; reject admin actions unless call.from_user.id == ADMIN_CHAT_ID.
🛡️ Proposed guard
def handle_all_callbacks(call):
data = call.data.split('_')
action = data[0]
+
+ if action in {"add", "rej", "admin"} and call.from_user.id != ADMIN_CHAT_ID:
+ bot.answer_callback_query(call.id, "Unauthorized", show_alert=True)
+ return📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @bot.callback_query_handler(func=lambda call: True) | |
| def handle_all_callbacks(call): | |
| data = call.data.split('_') | |
| action = data[0] | |
| if action == "add": | |
| amount, target_user = int(data[1]), int(data[2]) | |
| if target_user not in user_balances: user_balances[target_user] = 0 | |
| user_balances[target_user] += amount | |
| save_balances() | |
| bot.send_message(target_user, f"🎉 Balance Loaded! Added {amount} PKR. Total: {user_balances[target_user]} PKR.") | |
| bot.edit_message_caption(f"✅ Added {amount} PKR to {target_user}", chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "rej" and data[1] == "bal": | |
| target_user = int(data[2]) | |
| bot.send_message(target_user, "❌ Aapka screenshot reject kar diya gaya hai.") | |
| bot.edit_message_caption("❌ Screenshot Rejected", chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "admin" and data[1] == "sendnum": | |
| target_user = data[2] | |
| msg = bot.send_message(ADMIN_CHAT_ID, f"✍️ Is user `{target_user}` ke liye Number likh kar send karein:") | |
| bot.register_next_step_handler(msg, process_admin_number, target_user) | |
| bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "user" and data[1] == "reqotp": | |
| target_user = data[2] | |
| markup = types.InlineKeyboardMarkup() | |
| markup.add(types.InlineKeyboardButton("🔑 Send OTP", callback_data=f"admin_sendotp_{target_user}")) | |
| bot.send_message(ADMIN_CHAT_ID, f"📩 **ALERT!** User `{target_user}` OTP maang raha hai!", reply_markup=markup) | |
| bot.edit_message_text("⏳ OTP Request Sent to Admin. Waiting...", chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "admin" and data[1] == "sendotp": | |
| target_user = data[2] | |
| msg = bot.send_message(ADMIN_CHAT_ID, f"✍️ User `{target_user}` ke liye OTP Code likh kar send karein:") | |
| bot.register_next_step_handler(msg, process_admin_otp, target_user) | |
| bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "admin" and data[1] == "finish": | |
| target_user = int(data[2]) | |
| `@bot.callback_query_handler`(func=lambda call: True) | |
| def handle_all_callbacks(call): | |
| data = call.data.split('_') | |
| action = data[0] | |
| if action in {"add", "rej", "admin"} and call.from_user.id != ADMIN_CHAT_ID: | |
| bot.answer_callback_query(call.id, "Unauthorized", show_alert=True) | |
| return | |
| if action == "add": | |
| amount, target_user = int(data[1]), int(data[2]) | |
| if target_user not in user_balances: user_balances[target_user] = 0 | |
| user_balances[target_user] += amount | |
| save_balances() | |
| bot.send_message(target_user, f"🎉 Balance Loaded! Added {amount} PKR. Total: {user_balances[target_user]} PKR.") | |
| bot.edit_message_caption(f"✅ Added {amount} PKR to {target_user}", chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "rej" and data[1] == "bal": | |
| target_user = int(data[2]) | |
| bot.send_message(target_user, "❌ Aapka screenshot reject kar diya gaya hai.") | |
| bot.edit_message_caption("❌ Screenshot Rejected", chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "admin" and data[1] == "sendnum": | |
| target_user = data[2] | |
| msg = bot.send_message(ADMIN_CHAT_ID, f"✍️ Is user `{target_user}` ke liye Number likh kar send karein:") | |
| bot.register_next_step_handler(msg, process_admin_number, target_user) | |
| bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "user" and data[1] == "reqotp": | |
| target_user = data[2] | |
| markup = types.InlineKeyboardMarkup() | |
| markup.add(types.InlineKeyboardButton("🔑 Send OTP", callback_data=f"admin_sendotp_{target_user}")) | |
| bot.send_message(ADMIN_CHAT_ID, f"📩 **ALERT!** User `{target_user}` OTP maang raha hai!", reply_markup=markup) | |
| bot.edit_message_text("⏳ OTP Request Sent to Admin. Waiting...", chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "admin" and data[1] == "sendotp": | |
| target_user = data[2] | |
| msg = bot.send_message(ADMIN_CHAT_ID, f"✍️ User `{target_user}` ke liye OTP Code likh kar send karein:") | |
| bot.register_next_step_handler(msg, process_admin_otp, target_user) | |
| bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.message_id) | |
| elif action == "admin" and data[1] == "finish": | |
| target_user = int(data[2]) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 108 - 146, The handle_all_callbacks function
processes sensitive operations like balance additions, rejections, and OTP
sending without verifying that the user performing the action is the admin. Add
an authorization check comparing call.from_user.id against ADMIN_CHAT_ID at the
beginning of the function or before processing any admin-level actions (the
"add", "rej", "admin_*", and "user_reqotp" cases). If the user is not
authorized, reject the callback request with an appropriate error message
instead of proceeding with the operation.
| def process_admin_otp(message, target_user): | ||
| otp_text = message.text | ||
| bot.send_message(target_user, f"🔑 **Aapka WhatsApp OTP Code:** `{otp_text}`") | ||
| markup = types.InlineKeyboardMarkup() | ||
| markup.add(types.InlineKeyboardButton("💰 Cut Balance & Finish", callback_data=f"admin_finish_{target_user}")) | ||
| bot.send_message(ADMIN_CHAT_ID, f"📌 OTP bhej diya gaya hai. Balance Cut karein:", reply_markup=markup) |
There was a problem hiding this comment.
Debit or reserve balance before delivering the OTP.
process_admin_otp sends the OTP first, then relies on a later manual “Cut Balance & Finish” click. If that click is missed or fails, the user receives the product without being charged. Reserve funds when the order is created, or atomically debit before sending the OTP.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 164 - 169, The issue is that process_admin_otp
sends the OTP to the user before deducting their balance, creating a window
where the user could receive the product without payment if the admin's manual
"Cut Balance & Finish" action is missed or fails. Move the balance deduction or
reservation logic to execute before sending the OTP message (before the
bot.send_message call with the OTP text), ensuring the user's funds are
atomically debited or reserved before they receive the OTP and can access the
product.
| from flask import Flask | ||
| app = Flask('') | ||
| @app.route('/') | ||
| def home(): return "Bot is Alive!" | ||
|
|
||
| import threading | ||
| def run_db(): app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080))) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify Flask is declared in project dependencies.
# Expected result today: assertion failure unless pyproject.toml has been updated elsewhere.
python - <<'PY'
import pathlib
import tomllib
data = tomllib.loads(pathlib.Path("pyproject.toml").read_text(encoding="utf-8"))
deps = data.get("project", {}).get("dependencies", [])
print("\n".join(deps))
assert any(dep.lower().startswith("flask") for dep in deps), "Flask dependency is not declared"
PYRepository: aeither/telegram-bot-python
Length of output: 263
Add Flask to project dependencies in pyproject.toml.
The code imports Flask but it is not declared in the project dependencies. This will cause an import failure at runtime. Add flask as a dependency.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@railway.toml` around lines 171 - 177, The code imports the Flask module, but
Flask is not listed as a dependency in the project's pyproject.toml file, which
will cause an import failure at runtime. Add flask as a project dependency in
the dependencies section of pyproject.toml to ensure it is available when the
Flask import statement is executed.
Added a Telegram bot implementation with user balance management and product purchasing functionality.
Summary by CodeRabbit