Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Newbranch #1

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
60cf9f7
fixed the issue with usage_count
azimovu Jul 29, 2024
d2cc181
fixing use_count
azimovu Jul 29, 2024
7b8bbc8
fixed usage_count
azimovu Jul 29, 2024
1fb4cc0
added integration with click.uz
azimovu Aug 16, 2024
02719e7
fixed prices for discount
azimovu Aug 16, 2024
7296d98
web_server committed
azimovu Aug 24, 2024
28b1dc4
added more logging to the web server
azimovu Aug 25, 2024
05f55dc
some changes to click_integration
azimovu Sep 4, 2024
5ad72e6
added waitress
azimovu Sep 9, 2024
9a0fe3a
changed the click/-integration process
azimovu Sep 9, 2024
8f3d17e
fix: Add check for user state in handle_essay function to prevent unn…
azimovu Sep 11, 2024
bab40e0
fix: Move state reset to before API call in handle_essay function
azimovu Sep 11, 2024
aea93a8
refactor: remove duplicate command handlers and reorganize message ha…
azimovu Sep 11, 2024
184a5d5
feat: integrate Payme payment gateway and enhance user experience
azimovu Sep 11, 2024
73d0a0d
fix: Resolve invoice creation issue in Telegram bot by using send_mes…
azimovu Sep 11, 2024
7a18bfa
feat: Add Payme integration for subscription payments
azimovu Sep 11, 2024
66b4d07
fix: Add missing imports and fix invoice retrieval in bot_claude.py
azimovu Sep 11, 2024
1209d10
many changes
azimovu Sep 11, 2024
28bfb93
fix: Replace deprecated Updater with ApplicationBuilder
azimovu Sep 11, 2024
f98ae85
fix: add logging and exception handling to create_transaction functio…
azimovu Sep 11, 2024
027cd40
fix: add error handling and logging to transaction creation in handle…
azimovu Sep 11, 2024
90d3501
fix: correct usage of Updater and Application builder in bot_claude.py
azimovu Sep 11, 2024
0cc6ad7
fix: add logging and error handling to invoice creation process
azimovu Sep 11, 2024
5d10cfd
fix: handle unexpected response format in Paycom transaction creation
azimovu Sep 11, 2024
329dc5e
fix: correct Paycom API URL and improve config formatting
azimovu Sep 11, 2024
7266214
added some functions
azimovu Sep 12, 2024
e00f4d2
feat: Add CheckPerformTransaction method and improve create_transacti…
azimovu Sep 12, 2024
6547d5b
feat: Improve transaction handling
azimovu Sep 12, 2024
7d25351
changed gitignore
azimovu Sep 12, 2024
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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Ignore log files
*.log
*.log*

# But don't ignore important.log even if it's a log file
!important.log
Expand All @@ -13,4 +14,8 @@ __pycache__/
venv/

# Ignore
*.db
*.db
tree*
.aider*

*payme dev*
66 changes: 60 additions & 6 deletions bot_claude.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,68 @@
import logging
from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, filters
from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, filters, PreCheckoutQueryHandler, Updater, ContextTypes
from web_server import app
from config import TELEGRAM_BOT_TOKEN
from handlers import start, evaluate, feedback
from utils import user_management
from utils import user_management, paycom_integration
from database import migrate_database
from utils.paycom_integration import create_transaction
from config import PAYCOM_MERCHANT_ID
from handlers.start import handle_contact_shared
import threading
import asyncio

# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)

def run_flask():
app.run(host='0.0.0.0', port=5000)

async def pre_checkout_update(update: Updater, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Handle the pre-checkout update event."""
query = update.pre_checkout_query
await query.answer(ok=True)

async def invoice_callback(update: Updater, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Handle the invoice callback event."""
# Get the necessary information from the callback data
callback_data = update.callback_query.data
invoice_id = callback_data.split('_')[-1]

try:
# Retrieve the invoice details from the database or any other storage
invoice = user_management.get_invoice(invoice_id)
if not invoice:
await update.callback_query.answer(text="Invoice not found. Please try again.", show_alert=True)
return

# Create the invoice using the Payme API
transaction_data = await create_transaction(invoice['amount'], invoice['order_id'])
print(f"Transaction Data: {transaction_data}") # Debugging log

if transaction_data.get('result'):
transaction_id = transaction_data['result']['transaction']
payment_url = f"https://checkout.paycom.uz/{PAYCOM_MERCHANT_ID}/{transaction_id}"

# Send the invoice to the user with the payment URL
await update.callback_query.answer(url=payment_url)
else:
error_message = f"Failed to create the invoice: {transaction_data.get('error', 'Unknown error')}"
print(error_message) # Error log
await update.callback_query.answer(text=error_message, show_alert=True)
except Exception as e:
error_message = f"Exception during invoice creation: {e}"
print(error_message) # Exception log
await update.callback_query.answer(text=error_message, show_alert=True)

def main() -> None:
"""Start the bot."""
# Run database migration
migrate_database()

# Run Flask in a separate thread
flask_thread = threading.Thread(target=run_flask)
flask_thread.start()

application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()

Expand All @@ -24,18 +73,23 @@ def main() -> None:
application.add_handler(CommandHandler("purchase", user_management.show_purchase_options))
application.add_handler(CommandHandler("verify_payment", user_management.verify_payment))


application.add_handler(MessageHandler(filters.Regex('^Evaluate$'), user_management.handle_message))
application.add_handler(MessageHandler(filters.Regex('^Feedback$'), user_management.handle_message))
application.add_handler(MessageHandler(filters.Regex('^Check Remaining Uses$'), user_management.handle_check_remaining_uses))
application.add_handler(MessageHandler(filters.Regex('^Purchase More Uses$'), user_management.handle_message))
application.add_handler(MessageHandler(filters.Regex('^Purchase More Uses$'), user_management.show_purchase_options))
application.add_handler(MessageHandler(filters.Regex('^Verify Payment$'), user_management.verify_payment))
application.add_handler(MessageHandler(filters.CONTACT, user_management.handle_contact))
application.add_handler(MessageHandler(filters.CONTACT, handle_contact_shared))
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, user_management.handle_message))
application.add_handler(CallbackQueryHandler(user_management.handle_purchase_callback))

# Add the callback query handler for the "Pay Now" button click event
application.add_handler(CallbackQueryHandler(user_management.handle_purchase_callback, pattern='^purchase_'))
application.add_handler(CallbackQueryHandler(invoice_callback, pattern='^invoice_'))

# Add the pre-checkout query handler
application.add_handler(PreCheckoutQueryHandler(pre_checkout_update))

application.run_polling()

if __name__ == '__main__':
main()
main()
12 changes: 12 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,15 @@

# Database configuration
DB_NAME = 'users.db'

# Click config

CLICK_MERCHANT_ID = os.getenv('CLICK_MERCHANT_ID')
CLICK_SERVICE_ID = os.getenv('CLICK_SERVICE_ID')
CLICK_SECRET_KEY = os.getenv('CLICK_SECRET_KEY')
CLICK_MERCHANT_USER_ID = os.getenv('CLICK_MERCHANT_USER_ID')


# Payme config
PAYCOM_MERCHANT_ID = os.getenv('PAYCOM_MERCHANT_ID')
PAYCOM_SECRET_KEY = os.getenv('PAYCOM_SECRET_KEY')
77 changes: 77 additions & 0 deletions database.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sqlite3
from sqlite3 import Error
from config import DB_NAME

def migrate_database():
conn = create_connection()
if conn is not None:
Expand All @@ -16,6 +17,9 @@ def migrate_database():
if 'purchased_uses' not in columns:
cursor.execute("ALTER TABLE users ADD COLUMN purchased_uses INTEGER DEFAULT 0")

if 'usage_count' not in columns:
cursor.execute("ALTER TABLE users ADD COLUMN usage_count INTEGER DEFAULT 0")

conn.commit()
print("Database migration completed successfully.")
except Error as e:
Expand Down Expand Up @@ -49,6 +53,78 @@ def create_table(conn):
except Error as e:
print(e)

def create_transaction_table(conn):
try:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS transactions (
id TEXT PRIMARY KEY,
user_id INTEGER,
amount INTEGER,
state INTEGER,
create_time INTEGER,
perform_time INTEGER,
cancel_time INTEGER,
reason TEXT,
order_id TEXT,
FOREIGN KEY (user_id) REFERENCES users (id)
)
''')
except Error as e:
print(e)

def add_transaction(transaction_id, user_id, amount, state, create_time, order_id):
conn = create_connection()
sql = '''INSERT INTO transactions(id, user_id, amount, state, create_time, order_id)
VALUES(?, ?, ?, ?, ?, ?)'''
cur = conn.cursor()
cur.execute(sql, (transaction_id, user_id, amount, state, create_time, order_id))
conn.commit()
conn.close()

def get_transaction(transaction_id):
conn = create_connection()
cur = conn.cursor()
cur.execute("SELECT * FROM transactions WHERE id = ?", (transaction_id,))
transaction = cur.fetchone()
conn.close()
return transaction

def update_transaction(transaction_id, state, perform_time=None, cancel_time=None, reason=None):
conn = create_connection()
sql = '''UPDATE transactions
SET state = ?, perform_time = ?, cancel_time = ?, reason = ?
WHERE id = ?'''
cur = conn.cursor()
cur.execute(sql, (state, perform_time, cancel_time, reason, transaction_id))
conn.commit()
conn.close()


def get_order(order_id):
conn = create_connection()
cur = conn.cursor()
cur.execute("SELECT * FROM transactions WHERE order_id = ?", (order_id,))
order = cur.fetchone()
conn.close()
return order

def increment_usage_count(user_id):
conn = create_connection()
sql = ''' UPDATE users SET usage_count = usage_count + 1 WHERE id = ? '''
cur = conn.cursor()
cur.execute(sql, (user_id,))
conn.commit()
conn.close()

def get_usage_count(user_id):
conn = create_connection()
cur = conn.cursor()
cur.execute("SELECT usage_count FROM users WHERE id = ?", (user_id,))
result = cur.fetchone()
conn.close()
return result[0] if result else 0

def get_user(user_id):
conn = create_connection()
cur = conn.cursor()
Expand Down Expand Up @@ -117,6 +193,7 @@ def add_purchased_uses(user_id, amount):
conn = create_connection()
if conn is not None:
create_table(conn)
create_transaction_table(conn)
conn.close()
else:
print("Error! Cannot create the database connection.")
10 changes: 7 additions & 3 deletions handlers/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ async def handle_essay(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
topic = context.user_data.get('topic')
essay = update.message.text

# Check if the user's state is still 'waiting_for_topic'
if context.user_data.get('state') != 'waiting_for_topic':
return

# Reset state
context.user_data.clear()

# Check and decrement uses before making the API call
if await check_and_decrement_uses(user_id):
analysis_result = await essay_analysis.analyze_essay(topic, essay)
await update.message.reply_text(f"*Analysis Result:*\n\n{analysis_result}", parse_mode='Markdown')
else:
await handle_insufficient_uses(update, context)

# Reset state
context.user_data.clear()
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
python-telegram-bot
requests
python-dotenv
sqlite3
anthropic
waitress
aiohttp
Binary file modified tree.txt
Binary file not shown.
52 changes: 52 additions & 0 deletions utils/click_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import aiohttp
import hashlib
import time
from uuid import uuid4
import logging
from config import CLICK_MERCHANT_ID, CLICK_SERVICE_ID, CLICK_SECRET_KEY

CLICK_API_URL = 'https://api.click.uz/v2/merchant/'

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

async def generate_auth_header():
timestamp = str(int(time.time()))
digest = hashlib.sha1((timestamp + CLICK_SECRET_KEY).encode()).hexdigest()
auth_header = f'{CLICK_MERCHANT_ID}:{digest}:{timestamp}'
return {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Auth': auth_header
}

async def create_invoice(amount, phone_number):
merchant_trans_id = str(uuid4())
auth_header = await generate_auth_header()
data = {
"service_id": CLICK_SERVICE_ID,
"amount": amount,
"phone_number": phone_number,
"merchant_trans_id": merchant_trans_id,
"return_url": "http://www.uzielts.uz/click/complete"
}

async with aiohttp.ClientSession() as session:
async with session.post(f"{CLICK_API_URL}invoice/create", headers=auth_header, json=data) as response:
return await response.json(), merchant_trans_id

async def check_invoice_status(invoice_id):
auth_header = await generate_auth_header()
url = f"{CLICK_API_URL}invoice/status/{CLICK_SERVICE_ID}/{invoice_id}"

async with aiohttp.ClientSession() as session:
async with session.get(url, headers=auth_header) as response:
return await response.json()

async def check_payment_status(payment_id):
auth_header = await generate_auth_header()
url = f"{CLICK_API_URL}payment/status/{CLICK_SERVICE_ID}/{payment_id}"

async with aiohttp.ClientSession() as session:
async with session.get(url, headers=auth_header) as response:
return await response.json()
Loading