From f03362c313e987d6d054dcb66626d6c284c90c55 Mon Sep 17 00:00:00 2001 From: Hosein Date: Thu, 1 Jan 2026 11:11:30 +0330 Subject: [PATCH] added delete option and simplified crud operation on teacher --- bot/callbacks/students.py | 4 +- bot/callbacks/teachers.py | 216 ++++++++++++++++++-------------------- bot/handlers/students.py | 5 + bot/utils/crud_helpers.py | 11 ++ database/models.py | 21 ++++ 5 files changed, 143 insertions(+), 114 deletions(-) create mode 100644 bot/utils/crud_helpers.py diff --git a/bot/callbacks/students.py b/bot/callbacks/students.py index e7006cd..278f56e 100644 --- a/bot/callbacks/students.py +++ b/bot/callbacks/students.py @@ -1,6 +1,7 @@ from telebot import types from database.models import Students from bot.utils.formatters import format_student_info +from bot.utils.crud_helpers import create_entity_markup def register(bot): @@ -11,7 +12,8 @@ def register(bot): if student: details = format_student_info(student) - markup = types.InlineKeyboardMarkup() + markup = create_entity_markup("student", student_id) + bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML") else: diff --git a/bot/callbacks/teachers.py b/bot/callbacks/teachers.py index 007b478..303d676 100644 --- a/bot/callbacks/teachers.py +++ b/bot/callbacks/teachers.py @@ -2,6 +2,7 @@ from telebot import types, TeleBot from database.models import Teachers from bot.utils.formatters import format_teacher_info from bot.handlers.start import startMarkup +from bot.utils.crud_helpers import create_entity_markup def register(bot: TeleBot): @@ -9,6 +10,27 @@ def register(bot: TeleBot): cancelMarkup.add(types.InlineKeyboardButton( "Cancel", callback_data="cancel")) + TEACHER_FIELDS = [ + ('name', "the teacher's name"), + ('email', "email"), + ('phone_number', "phone ()"), + ('password', "password"), + ('username', "username"), + ('birthday', "birthday (YY/MM/DD)"), + ('about_me', "about me"), + ('job_title', "job title"), + ] + EDITABLE_FIELDS = { + 'name': 2, + 'email': 4, + 'phone_number': 5, + 'password': 3, + 'username': 1, + 'birthday': 8, + 'about_me': 9, + 'job_title': 10 + } + # Showing details of a Teacher @bot.callback_query_handler(func=lambda call: call.data.startswith('teacher_')) def show_teacher_details(call): @@ -17,9 +39,8 @@ def register(bot: TeleBot): if teacher: details = format_teacher_info(teacher) - markup = types.InlineKeyboardMarkup() - markup.add(types.InlineKeyboardButton("Edit Teacher", - callback_data=f"edit_teacher_{teacher_id}", switch_inline_query_current_chat="A default name for the teacher...")) + markup = create_entity_markup("teacher", teacher_id) + bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML") else: @@ -31,85 +52,50 @@ def register(bot: TeleBot): @bot.callback_query_handler(func=lambda call: call.data == 'create_teacher') def start_teacher_creation(call): msg = bot.send_message(call.message.chat.id, - "Please enter the teacher's name:", reply_markup=cancelMarkup) - bot.register_next_step_handler( - msg, process_name_step) + "Please enter following data: (enter any key to start)", + reply_markup=cancelMarkup) + bot.register_next_step_handler(msg, collect_field, {}, 0) bot.answer_callback_query(call.id) - def process_name_step(message): - name = message.text - msg = bot.send_message( - message.chat.id, f"Name: {name}\n\nNow enter email:", reply_markup=cancelMarkup) - bot.register_next_step_handler(msg, process_email_step, name) + def collect_field(message, data, step): + # Save previous field + if step > 0: + field_name = TEACHER_FIELDS[step - 1][0] + data[field_name] = message.text - def process_email_step(message, name): - email = message.text - msg = bot.send_message( - message.chat.id, f"Email: {email}\n\nNow enter phone: ()", reply_markup=cancelMarkup) - bot.register_next_step_handler(msg, process_phone_step, name, email) + # Done collecting? + if step >= len(TEACHER_FIELDS): + show_confirmation(message, data) + return - def process_phone_step(message, name, email): - phone = message.text - msg = bot.send_message( - message.chat.id, f"Phone: {phone}\n\nNow enter password: ", reply_markup=cancelMarkup) - bot.register_next_step_handler( - msg, process_password_step, name, email, phone) - - def process_password_step(message, name, email, phone): - password = message.text - msg = bot.send_message( - message.chat.id, f"password: {password}\n\nNow enter username:", reply_markup=cancelMarkup) - bot.register_next_step_handler( - msg, process_username_step, name, email, phone, password) - - def process_username_step(message, name, email, phone, password): - username = message.text - msg = bot.send_message( - message.chat.id, f"username: {username}\n\nNow enter birthday: (YY/MM/DD)", reply_markup=cancelMarkup) - bot.register_next_step_handler( - msg, process_birthday_step, name, email, phone, password, username) - - def process_birthday_step(message, name, email, phone, password, username): - birthday = message.text - msg = bot.send_message( - message.chat.id, f"birthday: {birthday}\n\nNow enter about me: ", reply_markup=cancelMarkup) - bot.register_next_step_handler( - msg, process_aboutme_step, name, email, phone, password, username, birthday) - - def process_aboutme_step(message, name, email, phone, password, username, birthday): - about_me = message.text - msg = bot.send_message( - message.chat.id, f"about me: {about_me}\n\nNow enter job title: ", reply_markup=cancelMarkup) - bot.register_next_step_handler( - msg, process_jobtitle_step, name, email, phone, password, username, birthday, about_me) - - def process_jobtitle_step(message, name, email, phone, password, username, birthday, about_me): - job_title = message.text - msg = bot.send_message(message.chat.id, "is this correct? (enter any key) (Use Cancel to Stop creating)\n" - f"Name: {name}\n" - f"Email: {email}\n" - f"Phone: {phone}\n" - f"Password: {password}\n" - f"Birthday: {birthday}\n" - f"About Me: {about_me}\n" - f"Job Title: {job_title}", + # Ask next question + field_name, prompt = TEACHER_FIELDS[step] + msg = bot.send_message(message.chat.id, f"Now enter {prompt}:", reply_markup=cancelMarkup) + bot.register_next_step_handler(msg, collect_field, data, step + 1) - bot.register_next_step_handler( - msg, confirm_teacher_creation, name, email, phone, password, username, birthday, about_me, job_title) + def show_confirmation(message, data): + summary = "Is this correct? (enter any key to continue or cancel to exit)\n\n" + "\n".join( + f"{name.replace('_', ' ').title()}: {data[name]}" + for name, _ in TEACHER_FIELDS + ) + msg = bot.send_message(message.chat.id, summary, + reply_markup=cancelMarkup) + bot.register_next_step_handler(msg, create_teacher, data) - def confirm_teacher_creation(message, name, email, phone, password, username, birthday, about_me, job_title): - if (Teachers.createTeacher(name=name, email=email, phone_number=phone, - password=password, username=username, birthday=birthday, - about_me=about_me, job_title=job_title)): - bot.send_message(message.chat.id, "✅ Teacher created!") + def create_teacher(message, data): + if Teachers.createTeacher(**data): + bot.send_message(message.chat.id, "✅ Teacher created!", + reply_markup=startMarkup()) else: - bot.send_message(message.chat.id, "❌ Failed to create teacher.") + bot.send_message( + message.chat.id, "❌ Failed to create teacher.", reply_markup=startMarkup()) @bot.callback_query_handler(func=lambda call: call.data == 'cancel') def cancel_action(call): bot.clear_step_handler(call.message) - bot.send_message(call.message.chat.id, "Action cancelled.") + bot.send_message(call.message.chat.id, + "Action cancelled.", reply_markup=startMarkup()) bot.answer_callback_query(call.id) # Editing a Teacher Flow @@ -118,64 +104,68 @@ def register(bot: TeleBot): teacher_id = call.data.split('_')[2] teacher = Teachers.getTeachertById(teacher_id) - editMarkup = types.ReplyKeyboardMarkup( - resize_keyboard=True, one_time_keyboard=True) - - for field in ['name', 'email', 'phone_number', 'password', 'username', 'birthday', 'about_me', 'job_title', 'Cancel']: - editMarkup.add(types.KeyboardButton(field.capitalize())) - - if teacher: - msg = bot.send_message(call.message.chat.id, - "Please enter the field you want to edit: ", reply_markup=editMarkup) - - bot.register_next_step_handler( - msg, process_field_select_step, teacher) - else: + if not teacher: bot.send_message(call.message.chat.id, "Teacher not found.") - - bot.answer_callback_query(call.id) - - def process_field_select_step(message, teacher: tuple): - field = message.text.lower() - if field == 'cancel': - bot.send_message(message.chat.id, "Action cancelled.") + bot.answer_callback_query(call.id) return - fields = ['id', 'username', 'name', 'created_at', 'email', 'phone_number', 'last_seen', 'is_verfied', - 'birthday', 'about_me', 'job_title'] - fields_index = {field: i for i, field in enumerate(fields)} + editMarkup = types.ReplyKeyboardMarkup( + resize_keyboard=True, one_time_keyboard=True) + for field in list(EDITABLE_FIELDS.keys()) + ['Cancel']: + editMarkup.add(types.KeyboardButton(field.capitalize())) - if field in fields: - previous_value = teacher[fields_index[field]] + msg = bot.send_message(call.message.chat.id, + "Please enter the field you want to edit: ", reply_markup=editMarkup) - markup = types.ReplyKeyboardMarkup( - resize_keyboard=True, one_time_keyboard=True, row_width=1) - markup.add(types.KeyboardButton( - f"{previous_value} (current)"), types.KeyboardButton("Cancel")) + bot.register_next_step_handler( + msg, process_field_select, teacher) + bot.answer_callback_query(call.id) - msg = bot.send_message( - message.chat.id, f"Please enter new value for {field}:", reply_markup=markup) - bot.register_next_step_handler( - msg, process_value_edit_step, teacher[fields_index["id"]], field, previous_value) - else: - bot.send_message( - message.chat.id, "Invalid field. Action cancelled.") - - def process_value_edit_step(message, teacher_id, field, previous_value): - new_value = message.text - if (new_value.lower() == 'cancel'): + def process_field_select(message, teacher: tuple): + field = message.text.lower() + if field == 'cancel': bot.send_message(message.chat.id, "Action cancelled.", reply_markup=startMarkup()) return - if (new_value == f"{previous_value} (current)"): + if field not in EDITABLE_FIELDS: bot.send_message( - message.chat.id, f"No changes made to Teacher's {field}.", reply_markup=startMarkup()) + message.chat.id, "Invalid field. Action cancelled.") return - if (Teachers.updateTeacher(teacher_id, **{field: new_value})): + current_value = teacher[EDITABLE_FIELDS[field]] + + msg = bot.send_message( + message.chat.id, f"Current value is: {current_value}.\n Please enter new value for {field}:", reply_markup=cancelMarkup) + bot.register_next_step_handler( + msg, process_value_edit, teacher[0], field, current_value) + + def process_value_edit(message, teacher_id, field, previous_value): + new_value = message.text + + # Handle cancellation + if new_value.lower() == 'cancel' or new_value == f"{previous_value} (current)": + msg = "Action cancelled." if new_value.lower( + ) == 'cancel' else f"No changes made to {field}." + bot.send_message(message.chat.id, msg, reply_markup=startMarkup()) + return + + # Update teacher + if Teachers.updateTeacher(teacher_id, **{field: new_value}): bot.send_message( message.chat.id, f"✅ Teacher's {field} updated successfully.", reply_markup=startMarkup()) else: bot.send_message( message.chat.id, f"❌ Failed to update Teacher's {field}.", reply_markup=startMarkup()) + + # Deleting a Teacher + @bot.callback_query_handler(func=lambda call: call.data.startswith('delete_teacher_')) + def delete_teacher(call): + teacher_id = call.data.split('_')[2] + if (Teachers.deleteTeacher(teacher_id)): + bot.send_message(call.message.chat.id, "✅ Teacher deleted.", + reply_markup=startMarkup()) + else: + bot.send_message(call.message.chat.id, "❌ Failed to delete Teacher.", + reply_markup=startMarkup()) + bot.answer_callback_query(call.id) diff --git a/bot/handlers/students.py b/bot/handlers/students.py index 1d0c98d..4d8e616 100644 --- a/bot/handlers/students.py +++ b/bot/handlers/students.py @@ -17,6 +17,11 @@ def register(bot): btn = types.InlineKeyboardButton( f"@{row[1]} | id#{row[0]}", callback_data=f"student_{row[0]}") markup.add(btn) + + # add button for creating a new student + markup.add(types.InlineKeyboardButton( + "➕ Create New Student", callback_data="create_student")) + bot.send_message( message.chat.id, "Here is the data:", reply_markup=markup) else: diff --git a/bot/utils/crud_helpers.py b/bot/utils/crud_helpers.py new file mode 100644 index 0000000..21a78f4 --- /dev/null +++ b/bot/utils/crud_helpers.py @@ -0,0 +1,11 @@ +from telebot import types + + +def create_entity_markup(entity_name, enitity_id): + markup = types.InlineKeyboardMarkup() + markup.add(types.InlineKeyboardButton( + f"✏️ Edit {entity_name}", callback_data=f"edit_{entity_name}_{enitity_id}")) + markup.add(types.InlineKeyboardButton( + f"🗑️ Delete {entity_name}", callback_data=f"delete_{entity_name}_{enitity_id}")) + + return markup diff --git a/database/models.py b/database/models.py index 73aba40..97cdfe0 100644 --- a/database/models.py +++ b/database/models.py @@ -154,3 +154,24 @@ class Teachers: finally: if conn: connection.release_db_connection(conn) + + def deleteTeacher(teacher_id): + conn = None + try: + conn = connection.get_db_connection() + if not conn: + return False + + cursor = conn.cursor() + cursor.execute( + "DELETE FROM teachers WHERE id = %s", (teacher_id,)) + conn.commit() + cursor.close() + + return True + except Exception as e: + logger.error(f"Database query error in deleteTeacher: {e}") + return False + finally: + if conn: + connection.release_db_connection(conn)