added CRUD for Students
This commit is contained in:
+136
-2
@@ -1,10 +1,33 @@
|
|||||||
from telebot import types
|
from telebot import types, TeleBot
|
||||||
from database.models import Students
|
from database.models import Students
|
||||||
from bot.utils.formatters import format_student_info
|
from bot.utils.formatters import format_student_info
|
||||||
from bot.utils.crud_helpers import create_entity_markup
|
from bot.utils.crud_helpers import create_entity_markup
|
||||||
|
from bot.handlers.start import startMarkup
|
||||||
|
|
||||||
|
|
||||||
def register(bot):
|
def register(bot: TeleBot):
|
||||||
|
cancelMarkup = types.InlineKeyboardMarkup()
|
||||||
|
cancelMarkup.add(types.InlineKeyboardButton(
|
||||||
|
"Cancel", callback_data="cancel"))
|
||||||
|
|
||||||
|
STUDENT_FIELDS = [
|
||||||
|
('name', "the student's name"),
|
||||||
|
('email', "email"),
|
||||||
|
('phone_number', "phone (<Optional>)"),
|
||||||
|
('password', "password"),
|
||||||
|
('username', "username"),
|
||||||
|
('birthday', "birthday (YY/MM/DD)"),
|
||||||
|
]
|
||||||
|
EDITABLE_FIELDS = {
|
||||||
|
'name': 2,
|
||||||
|
'email': 4,
|
||||||
|
'phone_number': 5,
|
||||||
|
'password': 3,
|
||||||
|
'username': 1,
|
||||||
|
'birthday': 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Showing details of a Student
|
||||||
@bot.callback_query_handler(func=lambda call: call.data.startswith('student_'))
|
@bot.callback_query_handler(func=lambda call: call.data.startswith('student_'))
|
||||||
def show_student_details(call):
|
def show_student_details(call):
|
||||||
student_id = call.data.split('_')[1]
|
student_id = call.data.split('_')[1]
|
||||||
@@ -20,3 +43,114 @@ def register(bot):
|
|||||||
bot.send_message(call.message.chat.id, "Student not found.")
|
bot.send_message(call.message.chat.id, "Student not found.")
|
||||||
|
|
||||||
bot.answer_callback_query(call.id)
|
bot.answer_callback_query(call.id)
|
||||||
|
|
||||||
|
# Creating a Student Flow
|
||||||
|
@bot.callback_query_handler(func=lambda call: call.data == 'create_student')
|
||||||
|
def create_student(call):
|
||||||
|
msg = bot.send_message(call.message.chat.id,
|
||||||
|
"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 collect_field(message, data, step):
|
||||||
|
# Save previous field
|
||||||
|
if step > 0:
|
||||||
|
field_name = STUDENT_FIELDS[step - 1][0]
|
||||||
|
data[field_name] = message.text
|
||||||
|
|
||||||
|
# Done collecting?
|
||||||
|
if step >= len(STUDENT_FIELDS):
|
||||||
|
show_confirmation(message, data)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ask next question
|
||||||
|
field_name, prompt = STUDENT_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)
|
||||||
|
|
||||||
|
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 STUDENT_FIELDS
|
||||||
|
)
|
||||||
|
msg = bot.send_message(message.chat.id, summary,
|
||||||
|
reply_markup=cancelMarkup)
|
||||||
|
bot.register_next_step_handler(msg, create_student, data)
|
||||||
|
|
||||||
|
def create_student(message, data):
|
||||||
|
if Students.createStudent(**data):
|
||||||
|
bot.send_message(message.chat.id, "✅ Student created!",
|
||||||
|
reply_markup=startMarkup())
|
||||||
|
else:
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, "❌ Failed to create student.", reply_markup=startMarkup())
|
||||||
|
|
||||||
|
# Editing a Student Flow
|
||||||
|
@bot.callback_query_handler(func=lambda call: call.data.startswith('edit_student_'))
|
||||||
|
def start_student_editing(call):
|
||||||
|
student_id = call.data.split('_')[2]
|
||||||
|
student = Students.getStudentById(student_id)
|
||||||
|
|
||||||
|
if not student:
|
||||||
|
bot.send_message(call.message.chat.id, "Student not found.")
|
||||||
|
bot.answer_callback_query(call.id)
|
||||||
|
return
|
||||||
|
|
||||||
|
editMarkup = types.ReplyKeyboardMarkup(
|
||||||
|
resize_keyboard=True, one_time_keyboard=True)
|
||||||
|
for field in list(EDITABLE_FIELDS.keys()) + ['Cancel']:
|
||||||
|
editMarkup.add(types.KeyboardButton(field.capitalize()))
|
||||||
|
|
||||||
|
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, student)
|
||||||
|
bot.answer_callback_query(call.id)
|
||||||
|
|
||||||
|
def process_field_select(message, student: tuple):
|
||||||
|
field = message.text.lower()
|
||||||
|
if field == 'cancel' or field not in EDITABLE_FIELDS:
|
||||||
|
msg = "Action cancelled." if field == 'cancel' else "Invalid field. Action cancelled."
|
||||||
|
bot.send_message(message.chat.id, msg,
|
||||||
|
reply_markup=startMarkup())
|
||||||
|
return
|
||||||
|
|
||||||
|
current_value = student[EDITABLE_FIELDS[field]]
|
||||||
|
|
||||||
|
msg = bot.send_message(
|
||||||
|
message.chat.id, f"Current value is: {current_value if field != 'password' else '********'}.\n Please enter new value for {field}:", reply_markup=cancelMarkup)
|
||||||
|
bot.register_next_step_handler(
|
||||||
|
msg, process_value_edit, student[0], field, current_value)
|
||||||
|
|
||||||
|
def process_value_edit(message, student_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 student
|
||||||
|
if Students.updateStudent(student_id, **{field: new_value}):
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, f"✅ Student's {field} updated successfully.", reply_markup=startMarkup())
|
||||||
|
else:
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, f"❌ Failed to update Student's {field}.", reply_markup=startMarkup())
|
||||||
|
|
||||||
|
# Deleting a Teacher
|
||||||
|
@bot.callback_query_handler(func=lambda call: call.data.startswith('delete_student_'))
|
||||||
|
def delete_student(call):
|
||||||
|
student_id = call.data.split('_')[2]
|
||||||
|
if (Students.deleteStudent(student_id)):
|
||||||
|
bot.send_message(call.message.chat.id, "✅ Student deleted.",
|
||||||
|
reply_markup=startMarkup())
|
||||||
|
else:
|
||||||
|
bot.send_message(call.message.chat.id, "❌ Failed to delete Student.",
|
||||||
|
reply_markup=startMarkup())
|
||||||
|
bot.answer_callback_query(call.id)
|
||||||
|
|||||||
@@ -123,20 +123,16 @@ def register(bot: TeleBot):
|
|||||||
|
|
||||||
def process_field_select(message, teacher: tuple):
|
def process_field_select(message, teacher: tuple):
|
||||||
field = message.text.lower()
|
field = message.text.lower()
|
||||||
if field == 'cancel':
|
if field == 'cancel' or field not in EDITABLE_FIELDS:
|
||||||
bot.send_message(message.chat.id, "Action cancelled.",
|
msg = "Action cancelled." if field == 'cancel' else "Invalid field. Action cancelled."
|
||||||
|
bot.send_message(message.chat.id, msg,
|
||||||
reply_markup=startMarkup())
|
reply_markup=startMarkup())
|
||||||
return
|
return
|
||||||
|
|
||||||
if field not in EDITABLE_FIELDS:
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id, "Invalid field. Action cancelled.")
|
|
||||||
return
|
|
||||||
|
|
||||||
current_value = teacher[EDITABLE_FIELDS[field]]
|
current_value = teacher[EDITABLE_FIELDS[field]]
|
||||||
|
|
||||||
msg = bot.send_message(
|
msg = bot.send_message(
|
||||||
message.chat.id, f"Current value is: {current_value}.\n Please enter new value for {field}:", reply_markup=cancelMarkup)
|
message.chat.id, f"Current value is: {current_value if field != 'password' else '********'}.\n Please enter new value for {field}:", reply_markup=cancelMarkup)
|
||||||
bot.register_next_step_handler(
|
bot.register_next_step_handler(
|
||||||
msg, process_value_edit, teacher[0], field, current_value)
|
msg, process_value_edit, teacher[0], field, current_value)
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,7 @@ def register(bot):
|
|||||||
bot.send_message(
|
bot.send_message(
|
||||||
message.chat.id, "Welcome! Use buttons to fetch from database.")
|
message.chat.id, "Welcome! Use buttons to fetch from database.")
|
||||||
|
|
||||||
markup = types.ReplyKeyboardMarkup(
|
markup = startMarkup()
|
||||||
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.",
|
bot.reply_to(message, "Use buttons to fetch from database.",
|
||||||
reply_markup=markup)
|
reply_markup=markup)
|
||||||
|
|
||||||
@@ -35,7 +28,7 @@ def startMarkup():
|
|||||||
btn1 = types.KeyboardButton("Show Students")
|
btn1 = types.KeyboardButton("Show Students")
|
||||||
btn2 = types.KeyboardButton("Show Teachers")
|
btn2 = types.KeyboardButton("Show Teachers")
|
||||||
btn3 = types.KeyboardButton("Show Courses")
|
btn3 = types.KeyboardButton("Show Courses")
|
||||||
btn4 = types.KeyboardButton("Show Tag")
|
btn4 = types.KeyboardButton("Show Tags")
|
||||||
btn5 = types.KeyboardButton("Show Categories")
|
btn5 = types.KeyboardButton("Show Categories")
|
||||||
markup.add(btn1, btn2, btn3, btn4, btn5)
|
markup.add(btn1, btn2, btn3, btn4, btn5)
|
||||||
return markup
|
return markup
|
||||||
|
|||||||
+90
-1
@@ -46,6 +46,94 @@ class Students:
|
|||||||
if conn:
|
if conn:
|
||||||
connection.release_db_connection(conn)
|
connection.release_db_connection(conn)
|
||||||
|
|
||||||
|
def createStudent(name, email, phone_number, password, username, birthday):
|
||||||
|
conn = None
|
||||||
|
try:
|
||||||
|
conn = connection.get_db_connection()
|
||||||
|
if not conn:
|
||||||
|
return False
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO students (name, email, phone_number, hashed_password, username, birthday) VALUES (%s, %s, %s, %s, %s, %s)",
|
||||||
|
(name, email, phone_number, password,
|
||||||
|
username, birthday)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Database query error in createStudent: {e}")
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if conn:
|
||||||
|
connection.release_db_connection(conn)
|
||||||
|
|
||||||
|
def updateStudent(student_id, **fields):
|
||||||
|
if not fields:
|
||||||
|
return False # nothing to update
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
try:
|
||||||
|
conn = connection.get_db_connection()
|
||||||
|
if not conn:
|
||||||
|
return False
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Build dynamic SET clause
|
||||||
|
columns = []
|
||||||
|
values = []
|
||||||
|
|
||||||
|
for key, value in fields.items():
|
||||||
|
columns.append(f"{key} = %s" if key !=
|
||||||
|
'password' else "hashed_password = %s")
|
||||||
|
values.append(value)
|
||||||
|
|
||||||
|
values.append(student_id)
|
||||||
|
|
||||||
|
query = f"""
|
||||||
|
UPDATE students
|
||||||
|
SET {', '.join(columns)}
|
||||||
|
WHERE id = %s
|
||||||
|
"""
|
||||||
|
|
||||||
|
cursor.execute(query, tuple(values))
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Database query error in updateStudent: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if conn:
|
||||||
|
connection.release_db_connection(conn)
|
||||||
|
|
||||||
|
def deleteStudent(student_id):
|
||||||
|
conn = None
|
||||||
|
try:
|
||||||
|
conn = connection.get_db_connection()
|
||||||
|
if not conn:
|
||||||
|
return False
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"DELETE FROM students WHERE id = %s", (student_id,))
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Database query error in deleteStudent: {e}")
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if conn:
|
||||||
|
connection.release_db_connection(conn)
|
||||||
|
|
||||||
|
|
||||||
class Teachers:
|
class Teachers:
|
||||||
def getAllTeachers():
|
def getAllTeachers():
|
||||||
@@ -130,7 +218,8 @@ class Teachers:
|
|||||||
values = []
|
values = []
|
||||||
|
|
||||||
for key, value in fields.items():
|
for key, value in fields.items():
|
||||||
columns.append(f"{key} = %s")
|
columns.append(f"{key} = %s" if key !=
|
||||||
|
'password' else "hashed_password = %s")
|
||||||
values.append(value)
|
values.append(value)
|
||||||
|
|
||||||
values.append(teacher_id)
|
values.append(teacher_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user