diff --git a/bot.py b/bot.py
deleted file mode 100644
index ea50357..0000000
--- a/bot.py
+++ /dev/null
@@ -1,142 +0,0 @@
-import os
-import logging
-from database.models import Students
-from telebot import types
-from datetime import datetime
-
-logger = logging.getLogger(__name__)
-
-authenticated_users = {2032936226}
-_bot = None
-
-def get_bot():
- global _bot
- if _bot is None:
- import telebot
- BOT_TOKEN = os.environ.get("BOT_TOKEN")
- _bot = telebot.TeleBot(BOT_TOKEN, threaded=False)
-
- @_bot.message_handler(commands=["start"])
- def start(message):
- if message.from_user.id in authenticated_users:
- _bot.reply_to(message, "authorized user! Welcome. Use /getstudents to fetch from database.")
- return
- _bot.reply_to(message, "Welcome! Use /getstudents to fetch from database.")
-
- @_bot.message_handler(commands=["getstudents"])
- def get_data(message):
- try:
- data = Students.getAllStudents()
- if data:
-
- markup = types.InlineKeyboardMarkup(row_width=2)
- for row in data:
- btn = types.InlineKeyboardButton(f"{row[0]}: @{row[1]}", callback_data=f"student_{row[0]}")
- markup.add(btn)
-
- _bot.send_message(message.chat.id, "Here is the data:", reply_markup=markup)
- else:
- _bot.reply_to(message, "No data found.")
- return
- except Exception as e:
- logger.error(f"Error in getdata handler: {e}")
- _bot.reply_to(message, "Sorry, an error occurred.")
-
- # Single handler for all student selections
- @_bot.callback_query_handler(func=lambda call: call.data.startswith('student_'))
- def show_student_details(call):
- student_id = call.data.split('_')[1]
- student = Students.getStudentById(student_id)
-
- if student:
- details = format_student_info(student)
- markup = types.InlineKeyboardMarkup()
- markup.add(types.InlineKeyboardButton("🔙 Back", callback_data="back_to_students"))
- _bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML")
- else:
- _bot.send_message(call.message.chat.id, "Student not found.")
-
- def format_student_info(student):
- """
- Format student data into a nice message
- student is a tuple: (id, username, created_at, email, phone_number, last_seen, is_verified, birthday)
- """
- print(student);
- id, username, created_at, email, phone_number, last_seen, is_verfied, birthday = student
-
- verified_status = "✅ Verified" if is_verfied else "❌ Not Verified"
-
- # Format dates nicely
- created_date = format_date(created_at)
- last_seen_date = format_date(last_seen)
-
- # Calculate age from birthday
- age = calculate_age(birthday)
-
- details = f"""
- 👤 Student Profile
-
- Username: {username}
- Email: {email}
- Phone: {phone_number}
- Birthday: {birthday} (Age: {age})
- Account Status: {verified_status}
-
- 📅 Account Info
- Joined: {created_date}
- Last Seen: {last_seen_date}
- ID: {id}
- """
- return details.strip()
-
- def format_date(date_string):
- """Convert database date to readable format"""
- if not date_string:
- return "N/A"
-
- try:
- # If date_string is already a datetime object
- if isinstance(date_string, datetime):
- return date_string.strftime("%d %b %Y, %H:%M")
-
- # If it's a string, parse it first
- date_obj = datetime.strptime(str(date_string), "%Y-%m-%d %H:%M:%S")
- return date_obj.strftime("%d %b %Y, %H:%M")
- except:
- return str(date_string)
-
- def calculate_age(birthday_string):
- """Calculate age from birthday"""
- if not birthday_string:
- return "N/A"
-
- try:
- birth_date = datetime.strptime(str(birthday_string), "%Y-%m-%d").date()
- today = datetime.now().date()
- age = today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))
- return age
- except:
- return "N/A"
-
-
- @_bot.message_handler(commands=["test"])
- def test_handler(message):
- markup = types.ReplyKeyboardMarkup(row_width=2, one_time_keyboard=True)
- btn1 = types.KeyboardButton("Option 1")
- btn2 = types.KeyboardButton("Option 2")
- markup.add(btn1, btn2)
- _bot.reply_to(message, "Test command received!", reply_markup=markup)
-
- @_bot.message_handler(func=lambda message: message.text in ["Option 1", "Option 2"])
- def handle_test_options(message):
- option = message.text
- _bot.send_message(message.chat.id, f"You selected: {option}")
-
- @_bot.message_handler(func=lambda message: True)
- def handle_student_selection(message):
- chat_id = message.chat.id
- selected_text = message.text
-
- _bot.reply_to(message, f"You said: {message.text}")
-
- return _bot
\ No newline at end of file
diff --git a/bot/bot.py b/bot/bot.py
new file mode 100644
index 0000000..cebc5fd
--- /dev/null
+++ b/bot/bot.py
@@ -0,0 +1,18 @@
+import os
+import telebot
+import logging
+from bot.handlers.init import register_all_handlers
+
+logger = logging.getLogger(__name__)
+
+_bot = None
+
+
+def get_bot():
+ global _bot
+ if _bot is None:
+ BOT_TOKEN = os.environ.get("BOT_TOKEN")
+ _bot = telebot.TeleBot(BOT_TOKEN, threaded=False)
+ register_all_handlers(_bot)
+ logger.info("Telegram bot initialized.")
+ return _bot
diff --git a/bot/callbacks/init.py b/bot/callbacks/init.py
new file mode 100644
index 0000000..217b108
--- /dev/null
+++ b/bot/callbacks/init.py
@@ -0,0 +1,7 @@
+from . import students, teachers
+
+
+def register_all_callbacks(bot):
+ """Register all callback handlers"""
+ students.register(bot)
+ teachers.register(bot)
diff --git a/bot/callbacks/students.py b/bot/callbacks/students.py
new file mode 100644
index 0000000..e7006cd
--- /dev/null
+++ b/bot/callbacks/students.py
@@ -0,0 +1,20 @@
+from telebot import types
+from database.models import Students
+from bot.utils.formatters import format_student_info
+
+
+def register(bot):
+ @bot.callback_query_handler(func=lambda call: call.data.startswith('student_'))
+ def show_student_details(call):
+ student_id = call.data.split('_')[1]
+ student = Students.getStudentById(student_id)
+
+ if student:
+ details = format_student_info(student)
+ markup = types.InlineKeyboardMarkup()
+ bot.send_message(call.message.chat.id, details,
+ reply_markup=markup, parse_mode="HTML")
+ else:
+ bot.send_message(call.message.chat.id, "Student not found.")
+
+ bot.answer_callback_query(call.id)
diff --git a/bot/callbacks/teachers.py b/bot/callbacks/teachers.py
new file mode 100644
index 0000000..b849ed5
--- /dev/null
+++ b/bot/callbacks/teachers.py
@@ -0,0 +1,20 @@
+from telebot import types
+from database.models import Teachers
+from bot.utils.formatters import format_teacher_info
+
+
+def register(bot):
+ @bot.callback_query_handler(func=lambda call: call.data.startswith('teacher_'))
+ def show_teacher_details(call):
+ teacher_id = call.data.split('_')[1]
+ teacher = Teachers.getTeachertById(teacher_id)
+
+ if teacher:
+ details = format_teacher_info(teacher)
+ markup = types.InlineKeyboardMarkup()
+ bot.send_message(call.message.chat.id, details,
+ reply_markup=markup, parse_mode="HTML")
+ else:
+ bot.send_message(call.message.chat.id, "Teacher not found.")
+
+ bot.answer_callback_query(call.id)
diff --git a/bot/handlers/common.py b/bot/handlers/common.py
new file mode 100644
index 0000000..0071466
--- /dev/null
+++ b/bot/handlers/common.py
@@ -0,0 +1,4 @@
+def register(bot):
+ @bot.message_handler(func=lambda message: True)
+ def handle_unknown(message):
+ bot.reply_to(message, f"You said: {message.text}")
diff --git a/bot/handlers/init.py b/bot/handlers/init.py
new file mode 100644
index 0000000..1085dad
--- /dev/null
+++ b/bot/handlers/init.py
@@ -0,0 +1,14 @@
+from . import start, students, teachers, common
+from bot.callbacks.init import register_all_callbacks
+
+
+def register_all_handlers(bot):
+ """Register all handlers and callbacks"""
+ # Message handlers
+ start.register(bot)
+ students.register(bot)
+ teachers.register(bot)
+ common.register(bot) # Must be last (catch-all)
+
+ # Callback handlers
+ register_all_callbacks(bot)
diff --git a/bot/handlers/start.py b/bot/handlers/start.py
new file mode 100644
index 0000000..90ece6b
--- /dev/null
+++ b/bot/handlers/start.py
@@ -0,0 +1,29 @@
+from telebot import types
+from bot.utils.auth import is_authenticated
+
+
+def register(bot):
+ @bot.message_handler(commands=["start"])
+ def start_handler(message):
+ if is_authenticated(message.from_user.id):
+ bot.send_message(
+ message.chat.id, "authorized user! Welcome.")
+ else:
+ bot.send_message(
+ message.chat.id, "Welcome! Use buttons to fetch from database.")
+
+ markup = types.ReplyKeyboardMarkup(
+ row_width=2, one_time_keyboard=True, resize_keyboard=True)
+ btn1 = types.KeyboardButton("Show Students")
+ btn2 = types.KeyboardButton("Show Teachers")
+ btn3 = types.KeyboardButton("Show Courses")
+ btn4 = types.KeyboardButton("Show Tag")
+ btn5 = types.KeyboardButton("Show Categories")
+ markup.add(btn1, btn2, btn3, btn4, btn5)
+ bot.reply_to(message, "Use buttons to fetch from database.",
+ reply_markup=markup)
+
+ @bot.message_handler(func=lambda message: message.text in ["Show Courses", "Show Tag", "Show Categories"])
+ def handle_test_options(message):
+ option = message.text
+ bot.send_message(message.chat.id, f"You selected: {option}")
diff --git a/bot/handlers/students.py b/bot/handlers/students.py
new file mode 100644
index 0000000..1d0c98d
--- /dev/null
+++ b/bot/handlers/students.py
@@ -0,0 +1,26 @@
+import logging
+from telebot import types
+from database.models import Students
+
+logger = logging.getLogger(__name__)
+
+
+def register(bot):
+ @bot.message_handler(func=lambda message: message.text == "Show Students")
+ def get_students(message):
+ try:
+ data = Students.getAllStudents()
+ if data:
+ markup = types.InlineKeyboardMarkup(row_width=2)
+
+ for row in data:
+ btn = types.InlineKeyboardButton(
+ f"@{row[1]} | id#{row[0]}", callback_data=f"student_{row[0]}")
+ markup.add(btn)
+ bot.send_message(
+ message.chat.id, "Here is the data:", reply_markup=markup)
+ else:
+ bot.reply_to(message, "No data found.")
+ except Exception as e:
+ logger.error(f"Error in get_students handler: {e}")
+ bot.reply_to(message, "Sorry, an error occurred.")
diff --git a/bot/handlers/teachers.py b/bot/handlers/teachers.py
new file mode 100644
index 0000000..109751f
--- /dev/null
+++ b/bot/handlers/teachers.py
@@ -0,0 +1,26 @@
+import logging
+from telebot import types
+from database.models import Teachers
+
+logger = logging.getLogger(__name__)
+
+
+def register(bot):
+ @bot.message_handler(func=lambda message: message.text == "Show Teachers")
+ def get_teachers(message):
+ try:
+ data = Teachers.getAllTeachers()
+ if data:
+
+ markup = types.InlineKeyboardMarkup(row_width=2)
+ for row in data:
+ btn = types.InlineKeyboardButton(
+ f"@{row[1]} | id#{row[0]}", callback_data=f"teacher_{row[0]}")
+ markup.add(btn)
+ bot.send_message(
+ message.chat.id, "Here is the data:", reply_markup=markup)
+ else:
+ bot.reply_to(message, "No data found.")
+ except Exception as e:
+ logger.error(f"Error in get_teachers handler: {e}")
+ bot.reply_to(message, "Sorry, an error occurred.")
diff --git a/bot/utils/auth.py b/bot/utils/auth.py
new file mode 100644
index 0000000..38165f1
--- /dev/null
+++ b/bot/utils/auth.py
@@ -0,0 +1,4 @@
+authenticated_users = {2032936226}
+
+def is_authenticated(user_id):
+ return user_id in authenticated_users
\ No newline at end of file
diff --git a/bot/utils/formatters.py b/bot/utils/formatters.py
new file mode 100644
index 0000000..b9ac134
--- /dev/null
+++ b/bot/utils/formatters.py
@@ -0,0 +1,109 @@
+from datetime import datetime
+
+
+def format_date(date_string):
+ """Convert database date to readable format"""
+ if not date_string:
+ return "N/A"
+
+ try:
+ # If date_string is already a datetime object
+ if isinstance(date_string, datetime):
+ return date_string.strftime("%d %b %Y, %H:%M")
+
+ # If it's a string, parse it first
+ date_obj = datetime.strptime(str(date_string), "%Y-%m-%d %H:%M:%S")
+ return date_obj.strftime("%d %b %Y, %H:%M")
+ except:
+ return str(date_string)
+
+
+def calculate_age(birthday_string):
+ """Calculate age from birthday"""
+ if not birthday_string:
+ return "N/A"
+
+ try:
+ birth_date = datetime.strptime(str(birthday_string), "%Y-%m-%d").date()
+ today = datetime.now().date()
+ age = today.year - birth_date.year - \
+ ((today.month, today.day) < (birth_date.month, birth_date.day))
+ return age
+ except:
+ return "N/A"
+
+# Student Info Formatter
+
+
+def format_student_info(student):
+ """
+ Format student data into a nice message
+ student is a tuple: (id, username, name, created_at, email, phone_number, last_seen, is_verified, birthday)
+ """
+ print(student)
+ id, username, name, created_at, email, phone_number, last_seen, is_verfied, birthday = student
+
+ verified_status = "✅ Verified" if is_verfied else "❌ Not Verified"
+
+ # Format dates nicely
+ created_date = format_date(created_at)
+ last_seen_date = format_date(last_seen)
+
+ # Calculate age from birthday
+ age = calculate_age(birthday)
+
+ details = f"""
+ 👤 Student Profile
+
+ Name: {name}
+ Username: {username}
+ Email: {email}
+ Phone: {phone_number}
+ Birthday: {birthday} (Age: {age})
+ Account Status: {verified_status}
+
+ 📅 Account Info
+ Joined: {created_date}
+ Last Seen: {last_seen_date}
+ ID: {id}
+ """
+ return details.strip()
+
+
+# Teacher Info Formatter
+def format_teacher_info(teacher):
+ """
+ Format student data into a nice message
+ student is a tuple: (id, username, created_at, email, phone_number, last_seen, is_verified, birthday)
+ """
+ print(teacher)
+ id, username, name, created_at, email, phone_number, last_seen, is_verfied, birthday, about_me, job_title = teacher
+
+ verified_status = "✅ Verified" if is_verfied else "❌ Not Verified"
+
+ # Format dates nicely
+ created_date = format_date(created_at)
+ last_seen_date = format_date(last_seen)
+
+ # Calculate age from birthday
+ age = calculate_age(birthday)
+
+ details = f"""
+ 👤 Student Profile
+
+ Name: {name}
+ Username: {username}
+ Job Title: {job_title}
+ About Me: {about_me}
+
+ Email: {email}
+ Phone: {phone_number}
+ Birthday: {birthday} (Age: {age})
+ Account Status: {verified_status}
+
+ 📅 Account Info
+ Joined: {created_date}
+ Last Seen: {last_seen_date}
+ ID: {id}
+ """
+ return details.strip()
diff --git a/database/models.py b/database/models.py
index 21be51d..88d7fa9 100644
--- a/database/models.py
+++ b/database/models.py
@@ -11,9 +11,9 @@ class Students:
conn = connection.get_db_connection()
if not conn:
return None
-
+
cursor = conn.cursor()
- cursor.execute("SELECT id,name FROM students");
+ cursor.execute("SELECT id,username FROM students")
result = cursor.fetchall()
cursor.close()
@@ -31,9 +31,10 @@ class Students:
conn = connection.get_db_connection()
if not conn:
return None
-
+
cursor = conn.cursor()
- cursor.execute("SELECT id,username, created_at, email, phone_number, last_seen, is_verfied, birthday FROM students WHERE id = %s", (student_id,))
+ cursor.execute(
+ "SELECT id,username, name, created_at, email, phone_number, last_seen, is_verfied, birthday FROM students WHERE id = %s", (student_id,))
result = cursor.fetchall()
cursor.close()
@@ -43,4 +44,47 @@ class Students:
return None
finally:
if conn:
- connection.release_db_connection(conn)
\ No newline at end of file
+ connection.release_db_connection(conn)
+
+
+class Teachers:
+ def getAllTeachers():
+ conn = None
+ try:
+ conn = connection.get_db_connection()
+ if not conn:
+ return None
+
+ cursor = conn.cursor()
+ cursor.execute("SELECT id,username FROM teachers")
+ result = cursor.fetchall()
+ cursor.close()
+
+ return result if result else None
+ except Exception as e:
+ logger.error(f"Database query error in getAllTeachers: {e}")
+ return None
+ finally:
+ if conn:
+ connection.release_db_connection(conn)
+
+ def getTeachertById(teacher_id):
+ conn = None
+ try:
+ conn = connection.get_db_connection()
+ if not conn:
+ return None
+
+ cursor = conn.cursor()
+ cursor.execute(
+ "SELECT id,username, name, created_at, email, phone_number, last_seen, is_verfied, birthday, about_me, job_title FROM teachers WHERE id = %s", (teacher_id))
+ result = cursor.fetchall()
+ cursor.close()
+
+ return result[0] if result else None
+ except Exception as e:
+ logger.error(f"Database query error in getTeacherById: {e}")
+ return None
+ finally:
+ if conn:
+ connection.release_db_connection(conn)
diff --git a/dev.py b/dev.py
index ff0e83a..4288e74 100644
--- a/dev.py
+++ b/dev.py
@@ -1,6 +1,6 @@
import os
import requests
-from bot import get_bot
+from bot.bot import get_bot
from dotenv import load_dotenv
load_dotenv()
diff --git a/main.py b/main.py
index 9984f32..235ac42 100644
--- a/main.py
+++ b/main.py
@@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
async def telegram_webhook(request: Request):
try:
import telebot
- from bot import get_bot
+ from bot.bot import get_bot
bot = get_bot()
json_data = await request.json()