diff --git a/bot/callbacks/categories.py b/bot/callbacks/categories.py index 4e1e18d..6bc9d54 100644 --- a/bot/callbacks/categories.py +++ b/bot/callbacks/categories.py @@ -1,5 +1,5 @@ from telebot import types, TeleBot -from database.models import Categories +from database.models import Categories, Admins from bot.handlers.start import startMarkup from bot.utils.crud_helpers import create_entity_markup @@ -38,7 +38,7 @@ def register(bot: TeleBot): Description: \n{category[2]} """ details.strip() - markup = create_entity_markup("category", category_id) + markup = create_entity_markup("category", category_id, True) bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML") @@ -91,9 +91,13 @@ def register(bot: TeleBot): message.chat.id, "āŒ Failed to create category.", reply_markup=startMarkup()) # Editing a Category Flow - @bot.callback_query_handler(func=lambda call: call.data.startswith('edit_category_')) def start_category_editing(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + category_id = call.data.split('_')[2] category = Categories.getCategorieById(category_id) @@ -150,6 +154,11 @@ def register(bot: TeleBot): # Deleting a Category @bot.callback_query_handler(func=lambda call: call.data.startswith('delete_category_')) def delete_category(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + category_id = call.data.split('_')[2] if (Categories.deleteCategory(category_id)): bot.send_message(call.message.chat.id, "āœ… Category deleted.", diff --git a/bot/callbacks/courses.py b/bot/callbacks/courses.py index f8d6bf0..fd802c4 100644 --- a/bot/callbacks/courses.py +++ b/bot/callbacks/courses.py @@ -1,5 +1,5 @@ from telebot import TeleBot, types -from database.models import Courses +from database.models import Courses, Admins from bot.utils.crud_helpers import create_entity_markup from bot.utils.formatters import format_course_info from bot.handlers.start import startMarkup @@ -38,7 +38,7 @@ def register(bot: TeleBot): return details = format_course_info(course) - markup = create_entity_markup("course", course_id) + markup = create_entity_markup("course", course_id, True) markup.add(types.InlineKeyboardButton( f"šŸ‘Øā€šŸ« Teacher's Info", callback_data=f"teacher_{course[3]}")) @@ -93,6 +93,11 @@ def register(bot: TeleBot): # Editing a Course Flow @bot.callback_query_handler(func=lambda call: call.data.startswith('edit_course_')) def start_course_editing(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + course_id = call.data.split('_')[2] course = Courses.getCourseById(course_id) @@ -149,6 +154,11 @@ def register(bot: TeleBot): # Deleting a Teacher @bot.callback_query_handler(func=lambda call: call.data.startswith('delete_course_')) def delete_course(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + course_id = call.data.split('_')[2] if (Courses.deleteCourse(course_id)): bot.send_message(call.message.chat.id, "āœ… Course deleted.", diff --git a/bot/callbacks/students.py b/bot/callbacks/students.py index b464914..1baa0ed 100644 --- a/bot/callbacks/students.py +++ b/bot/callbacks/students.py @@ -1,5 +1,5 @@ from telebot import types, TeleBot -from database.models import Students +from database.models import Students, Admins from bot.utils.formatters import format_student_info from bot.utils.crud_helpers import create_entity_markup from bot.handlers.start import startMarkup @@ -30,12 +30,17 @@ def register(bot: TeleBot): # Showing details of a Student @bot.callback_query_handler(func=lambda call: call.data.startswith('student_')) def show_student_details(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + student_id = call.data.split('_')[1] student = Students.getStudentById(student_id) if student: details = format_student_info(student) - markup = create_entity_markup("student", student_id) + markup = create_entity_markup("student", student_id, True) bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML") @@ -47,6 +52,11 @@ def register(bot: TeleBot): # Creating a Student Flow @bot.callback_query_handler(func=lambda call: call.data == 'create_student') def create_student(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + msg = bot.send_message(call.message.chat.id, "Please enter following data: (enter any key to start)", reply_markup=cancelMarkup) @@ -90,6 +100,11 @@ def register(bot: TeleBot): # Editing a Student Flow @bot.callback_query_handler(func=lambda call: call.data.startswith('edit_student_')) def start_student_editing(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + student_id = call.data.split('_')[2] student = Students.getStudentById(student_id) @@ -146,6 +161,11 @@ def register(bot: TeleBot): # Deleting a Teacher @bot.callback_query_handler(func=lambda call: call.data.startswith('delete_student_')) def delete_student(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + student_id = call.data.split('_')[2] if (Students.deleteStudent(student_id)): bot.send_message(call.message.chat.id, "āœ… Student deleted.", diff --git a/bot/callbacks/tags.py b/bot/callbacks/tags.py index 70e2f57..5c9575e 100644 --- a/bot/callbacks/tags.py +++ b/bot/callbacks/tags.py @@ -1,5 +1,5 @@ from telebot import types, TeleBot -from database.models import Tags +from database.models import Tags, Admins from bot.handlers.start import startMarkup from bot.utils.crud_helpers import create_entity_markup @@ -34,7 +34,7 @@ def register(bot: TeleBot): slug: {tag[2]} """ details.strip() - markup = create_entity_markup("tag", tag_id) + markup = create_entity_markup("tag", tag_id, True) bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML") @@ -87,9 +87,13 @@ def register(bot: TeleBot): message.chat.id, "āŒ Failed to create tag.", reply_markup=startMarkup()) # Editing a Tag Flow - @bot.callback_query_handler(func=lambda call: call.data.startswith('edit_tag_')) def start_tag_editing(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + tag_id = call.data.split('_')[2] tag = Tags.getTagById(tag_id) @@ -146,6 +150,11 @@ def register(bot: TeleBot): # Deleting a Tag @bot.callback_query_handler(func=lambda call: call.data.startswith('delete_tag_')) def delete_tag(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + tag_id = call.data.split('_')[2] if (Tags.deleteTag(tag_id)): bot.send_message(call.message.chat.id, "āœ… Tag deleted.", diff --git a/bot/callbacks/teachers.py b/bot/callbacks/teachers.py index c71d1f0..63236dd 100644 --- a/bot/callbacks/teachers.py +++ b/bot/callbacks/teachers.py @@ -1,12 +1,11 @@ from telebot import types, TeleBot -from database.models import Teachers +from database.models import Teachers, Admins from bot.utils.formatters import format_teacher_info from bot.handlers.start import startMarkup from bot.utils.crud_helpers import create_entity_markup # TODO: Add Buttons for skipping Optional Fields (Add to all entities). -# TODO: Add Option for handling all updates at once. -# TODO: Add Authentication for sensitive actions and info. +# TODO: Add Option for handling all updates at once.\ # TODO: Add Option for seeing courses taught by a teacher in Teacher Details. @@ -45,7 +44,7 @@ def register(bot: TeleBot): if teacher: details = format_teacher_info(teacher) - markup = create_entity_markup("teacher", teacher_id) + markup = create_entity_markup("teacher", teacher_id, True) bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML") @@ -57,6 +56,11 @@ def register(bot: TeleBot): # Creating a Teacher Flow @bot.callback_query_handler(func=lambda call: call.data == 'create_teacher') def start_teacher_creation(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + msg = bot.send_message(call.message.chat.id, "Please enter following data: (enter any key to start)", reply_markup=cancelMarkup) @@ -100,6 +104,11 @@ def register(bot: TeleBot): # Editing a Teacher Flow @bot.callback_query_handler(func=lambda call: call.data.startswith('edit_teacher_')) def start_teacher_editing(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + teacher_id = call.data.split('_')[2] teacher = Teachers.getTeacherById(teacher_id) @@ -156,6 +165,11 @@ def register(bot: TeleBot): # Deleting a Teacher @bot.callback_query_handler(func=lambda call: call.data.startswith('delete_teacher_')) def delete_teacher(call): + if not Admins.is_authenticated(call.from_user.id): + bot.answer_callback_query(call.id, "ā›” Unauthorized access!") + bot.send_message(call.message.chat.id, "Please /login first.") + return + teacher_id = call.data.split('_')[2] if (Teachers.deleteTeacher(teacher_id)): bot.send_message(call.message.chat.id, "āœ… Teacher deleted.", diff --git a/bot/handlers/categories.py b/bot/handlers/categories.py index 4c7ac34..5bab5c2 100644 --- a/bot/handlers/categories.py +++ b/bot/handlers/categories.py @@ -25,7 +25,11 @@ def register(bot): bot.send_message( message.chat.id, "Here is the data:", reply_markup=markup) else: - bot.reply_to(message, "No data found.") + markup = types.InlineKeyboardMarkup(row_width=1) + markup.add(types.InlineKeyboardButton( + "āž• Create New Category", callback_data="create_category")) + + bot.reply_to(message, "No data found.", reply_markup=markup) except Exception as e: logger.error(f"Error in 'Show Categories' handler: {e}") bot.reply_to(message, "Sorry, an error occurred.") diff --git a/bot/handlers/common.py b/bot/handlers/common.py index 0071466..6229a4b 100644 --- a/bot/handlers/common.py +++ b/bot/handlers/common.py @@ -1,4 +1,9 @@ +from telebot import types +from bot.handlers.start import startMessage + + def register(bot): @bot.message_handler(func=lambda message: True) def handle_unknown(message): - bot.reply_to(message, f"You said: {message.text}") + bot.reply_to( + message, f"You said: {message.text}. send /start to get started.") diff --git a/bot/handlers/courses.py b/bot/handlers/courses.py index c424c0e..b6be6ac 100644 --- a/bot/handlers/courses.py +++ b/bot/handlers/courses.py @@ -24,7 +24,10 @@ def register(bot): bot.send_message( message.chat.id, "Here is the data:", reply_markup=markup) else: - bot.reply_to(message, "No data found.") + markup = types.InlineKeyboardMarkup(row_width=1) + markup.add(types.InlineKeyboardButton( + "āž• Create New Course", callback_data="create_course")) + bot.reply_to(message, "No data found.", reply_markup=markup) except Exception as e: logger.error(f"Error in (Show Courses) handler: {e}") bot.reply_to(message, "Sorry, an error occurred.") diff --git a/bot/handlers/init.py b/bot/handlers/init.py index 50b2f80..124cde3 100644 --- a/bot/handlers/init.py +++ b/bot/handlers/init.py @@ -1,11 +1,25 @@ -from . import start, students, teachers, courses, tags, categories, common +from . import start, students, teachers, courses, tags, categories, common, login from bot.callbacks.init import register_all_callbacks +from telebot import types def register_all_handlers(bot): """Register all handlers and callbacks""" + # Set bot commands + commands = [ + types.BotCommand(command="start", description="Start the bot"), + types.BotCommand(command="login", description="Login to your account"), + types.BotCommand(command="logout", + description="Logout of your account"), + types.BotCommand(command="session", + description="Info about your session"), + ] + + bot.set_my_commands(commands) + # Message handlers start.register(bot) + login.register(bot) students.register(bot) teachers.register(bot) courses.register(bot) diff --git a/bot/handlers/login.py b/bot/handlers/login.py new file mode 100644 index 0000000..49f93b1 --- /dev/null +++ b/bot/handlers/login.py @@ -0,0 +1,110 @@ +from telebot import types, TeleBot +from database.models import Admins +from bot.handlers.start import startMarkup + + +def register(bot: TeleBot): + + @bot.message_handler(commands=['login']) + def start_login(message): + # Check if already authenticated + if Admins.is_authenticated(message.from_user.id): + session_info = Admins.get_session_info(message.from_user.id) + bot.send_message( + message.chat.id, + f"āœ… You are already logged in!\n\n" + f"Session expires in: {session_info['time_remaining']}" + ) + return + + msg = bot.send_message( + message.chat.id, + "šŸ” Please enter your username:" + ) + bot.register_next_step_handler(msg, get_password) + + def get_password(message): + """Get username and ask for password""" + username = message.text.strip() + + try: + bot.delete_message(message.chat.id, message.message_id) + except: + pass + + msg = bot.send_message( + message.chat.id, + f"Username: {username}\n\nšŸ”‘ Now enter your password:" + ) + bot.register_next_step_handler(msg, verify_and_login, username) + + def verify_and_login(message, username): + """Verify credentials and create session""" + password = message.text.strip() + telegram_id = message.from_user.id + + try: + bot.delete_message(message.chat.id, message.message_id) + except: + pass + + # Attempt login (this creates the session) + if Admins.login(username, password, telegram_id): + bot.send_message( + message.chat.id, + f"āœ… Login successful!\n\n" + f"Welcome back, {username}!\n" + f"Session valid for: {Admins.SESSION_TIMEOUT_HOURS} hours\n" + f"Use /session for info about your session, or /logout to logout.", + reply_markup=startMarkup() + ) + else: + bot.send_message( + message.chat.id, + "āŒ Invalid credentials or unauthorized Telegram account.\n\n" + "Please check your username and password.\nContact @HoseinA05 for support." + ) + + @bot.message_handler(commands=['logout']) + def logout(message): + """Logout user manually""" + + if not Admins.is_authenticated(message.from_user.id): + bot.send_message(message.chat.id, "You are not logged in.") + return + + if Admins.logout(message.from_user.id): + bot.send_message( + message.chat.id, + "āœ… You have been logged out successfully.\n\n" + "Use /login to access admin features again." + ) + else: + bot.send_message( + message.chat.id, "āŒ Logout failed. Please try again later.") + + @bot.message_handler(commands=['session']) + def check_session(message): + """Check current session status""" + session_info = Admins.get_session_info(message.from_user.id) + + if not session_info: + bot.send_message( + message.chat.id, "āŒ You don't have an admin account.") + return + + if session_info['is_active']: + bot.send_message( + message.chat.id, + f"āœ… Active Session\n\n" + f"Username: {session_info['username']}\n" + f"Last Login: {session_info['last_login']}\n" + f"Time Remaining: {session_info['time_remaining']}" + ) + else: + bot.send_message( + message.chat.id, + f"ā±ļø Session Expired\n\n" + f"Username: {session_info['username']}\n" + f"Please use /login to continue." + ) diff --git a/bot/handlers/start.py b/bot/handlers/start.py index 19ee62c..b1277bf 100644 --- a/bot/handlers/start.py +++ b/bot/handlers/start.py @@ -1,5 +1,4 @@ from telebot import types -from bot.utils.auth import is_authenticated # TODO: Add Pagincation to Showing rows of entities (To all entities) @@ -7,16 +6,17 @@ 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.") + startMessage(bot, message=message) - markup = startMarkup() - bot.reply_to(message, "Use buttons to fetch from database.", - reply_markup=markup) + +def startMessage(bot, message): + # if is_authenticated(message.from_user.id): + # bot.send_message( + # message.chat.id, "authorized user! Welcome.") + + markup = startMarkup() + bot.reply_to(message, "Use buttons to fetch from database.", + reply_markup=markup) def startMarkup(): diff --git a/bot/handlers/students.py b/bot/handlers/students.py index 4d8e616..e9f53a9 100644 --- a/bot/handlers/students.py +++ b/bot/handlers/students.py @@ -1,13 +1,18 @@ import logging -from telebot import types -from database.models import Students +from telebot import types, TeleBot +from database.models import Students, Admins logger = logging.getLogger(__name__) -def register(bot): +def register(bot: TeleBot): @bot.message_handler(func=lambda message: message.text == "Show Students") def get_students(message): + if not Admins.is_authenticated(message.from_user.id): + bot.send_message( + message.chat.id, "ā›” Unauthorized access!\nPlease /login first.") + return + try: data = Students.getAllStudents() if data: @@ -20,12 +25,15 @@ def register(bot): # add button for creating a new student markup.add(types.InlineKeyboardButton( - "āž• Create New Student", callback_data="create_student")) + "āž• Create New Student šŸ”’", callback_data="create_student")) bot.send_message( message.chat.id, "Here is the data:", reply_markup=markup) else: - bot.reply_to(message, "No data found.") + markup = types.InlineKeyboardMarkup(row_width=1) + markup.add(types.InlineKeyboardButton( + "āž• Create New Student šŸ”’", callback_data="create_student")) + bot.reply_to(message, "No data found.", reply_markup=markup) 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/tags.py b/bot/handlers/tags.py index 29d22d5..9093f3e 100644 --- a/bot/handlers/tags.py +++ b/bot/handlers/tags.py @@ -25,11 +25,11 @@ def register(bot: TeleBot): bot.send_message( message.chat.id, "Here is the data:", reply_markup=markup) else: - markup = types.InlineKeyboardMarkup(row_width=2) + markup = types.InlineKeyboardMarkup(row_width=1) markup.add(types.InlineKeyboardButton( "āž• Create New Tag", callback_data="create_tag")) - bot.reply_to(message, "No data found.", markup=markup) + bot.reply_to(message, "No data found.", reply_markup=markup) except Exception as e: logger.error(f"Error in 'Show Tags' handler: {e}") bot.reply_to(message, "Sorry, an error occurred.") diff --git a/bot/handlers/teachers.py b/bot/handlers/teachers.py index 2240869..5f1e15e 100644 --- a/bot/handlers/teachers.py +++ b/bot/handlers/teachers.py @@ -19,12 +19,15 @@ def register(bot): markup.add(btn) # add button for creating a new teacher markup.add(types.InlineKeyboardButton( - "āž• Create New Teacher", callback_data="create_teacher")) + "āž• Create New Teacher šŸ”’", callback_data="create_teacher")) bot.send_message( message.chat.id, "Here is the data:", reply_markup=markup) else: - bot.reply_to(message, "No data found.") + markup = types.InlineKeyboardMarkup(row_width=1) + markup.add(types.InlineKeyboardButton( + "āž• Create New Teacher šŸ”’", callback_data="create_teacher")) + bot.reply_to(message, "No data found.", reply_markup=markup) 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 deleted file mode 100644 index 38165f1..0000000 --- a/bot/utils/auth.py +++ /dev/null @@ -1,4 +0,0 @@ -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/crud_helpers.py b/bot/utils/crud_helpers.py index 21a78f4..a12e1b2 100644 --- a/bot/utils/crud_helpers.py +++ b/bot/utils/crud_helpers.py @@ -1,11 +1,11 @@ from telebot import types -def create_entity_markup(entity_name, enitity_id): +def create_entity_markup(entity_name, enitity_id, is_auth_needed=False): markup = types.InlineKeyboardMarkup() markup.add(types.InlineKeyboardButton( - f"āœļø Edit {entity_name}", callback_data=f"edit_{entity_name}_{enitity_id}")) + f"āœļø Edit {entity_name} " + ("šŸ”’" if is_auth_needed else ""), callback_data=f"edit_{entity_name}_{enitity_id}")) markup.add(types.InlineKeyboardButton( - f"šŸ—‘ļø Delete {entity_name}", callback_data=f"delete_{entity_name}_{enitity_id}")) + f"šŸ—‘ļø Delete {entity_name}" + ("šŸ”’" if is_auth_needed else ""), callback_data=f"delete_{entity_name}_{enitity_id}")) return markup diff --git a/database/models.py b/database/models.py index 40eda7b..40ae1e2 100644 --- a/database/models.py +++ b/database/models.py @@ -1,6 +1,9 @@ import logging import database.connection as connection +import hashlib +from datetime import datetime, timedelta + logger = logging.getLogger(__name__) @@ -55,6 +58,119 @@ class BaseRepository: connection.release_db_connection(conn) +class Admins(BaseRepository): + + SESSION_TIMEOUT_HOURS = 1 + + @staticmethod + def hash_password(password: str) -> str: + """Hash password using SHA256""" + return hashlib.sha256(password.encode()).hexdigest() + + @staticmethod + def login(username: str, password: str, telegram_id: int) -> bool: + """ + Verify credentials and create a session. + Returns True if login successful, False otherwise. + """ + + def query(cursor): + password_hash = Admins.hash_password(password) + cursor.execute( + "SELECT id FROM admins WHERE username = %s AND password_hash = %s AND telegram_id = %s", + (username, password_hash, telegram_id) + ) + result = cursor.fetchone() + return result is not None + + result = Admins._execute_query(query, "login") + + if result: + # Create session by updating last_login and session_expires_at + def mutation(cursor, conn): + expires_at = datetime.now() + timedelta(hours=Admins.SESSION_TIMEOUT_HOURS) + cursor.execute( + """UPDATE admins + SET last_login = CURRENT_TIMESTAMP, + session_expires_at = %s + WHERE telegram_id = %s""", + (expires_at, telegram_id) + ) + + return Admins._execute_mutation(mutation, "login") + + return False + + @staticmethod + def is_authenticated(telegram_id: int) -> bool: + """Check if user has a valid active session""" + def query(cursor): + cursor.execute( + "SELECT session_expires_at FROM admins WHERE telegram_id = %s", + (telegram_id,) + ) + result = cursor.fetchone() + + if not result or result[0] is None: + return False + + # Check if session has expired + expires_at = result[0] + + if isinstance(expires_at, str): + expires_at = datetime.fromisoformat(expires_at) + + return datetime.now() < expires_at + + result = Admins._execute_query(query, "is_authenticated") + return result if result is not None else False + + @staticmethod + def logout(telegram_id: int) -> bool: + """Logout admin by clearing session""" + def mutation(cursor, conn): + cursor.execute( + "UPDATE admins SET session_expires_at = NULL WHERE telegram_id = %s", + (telegram_id,) + ) + + return Admins._execute_mutation(mutation, "logout") + + @staticmethod + def get_session_info(telegram_id: int) -> dict: + """Get session info for the admin""" + def query(cursor): + cursor.execute( + "SELECT username, last_login, session_expires_at FROM admins WHERE telegram_id = %s", + (telegram_id,) + ) + result = cursor.fetchone() + return result + + result = Admins._execute_query(query, "get_session_info") + if not result: + return None + + session_info = { + 'username': result[0], + 'last_login': result[1], + 'expires_at': result[2], + 'is_active': False + } + + if result[2]: + expires_at = result[2] + + if isinstance(expires_at, str): + expires_at = datetime.fromisoformat(expires_at) + + session_info['is_active'] = datetime.now() < expires_at + session_info['time_remaining'] = str( + expires_at - datetime.now()).split('.')[0] + + return session_info + + class Students(BaseRepository): table_name = "students" diff --git a/dev.py b/dev.py index 4288e74..9e40d9d 100644 --- a/dev.py +++ b/dev.py @@ -7,6 +7,7 @@ load_dotenv() BOT_TOKEN = os.environ.get("BOT_TOKEN") + def ensure_no_webhook(): """Remove webhook before starting polling""" response = requests.post( @@ -15,13 +16,13 @@ def ensure_no_webhook(): if response.json()['ok']: print("āœ… Webhook removed, starting polling...") return True - + print("āš ļø Warning: Could not remove webhook") return False - + if __name__ == "__main__": if ensure_no_webhook(): bot = get_bot() print("šŸ¤– Bot is polling locally...") - bot.polling(non_stop=True) \ No newline at end of file + bot.polling(non_stop=True)