344 lines
11 KiB
Python
344 lines
11 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
Enhanced Scheduler Bot with SQLite database support
|
|
"""
|
|
|
|
import sqlite3
|
|
import datetime
|
|
from telegram import Update
|
|
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
|
|
|
|
# 🔑 REPLACE THIS with your bot token from @BotFather
|
|
BOT_TOKEN = "8248686383:AAGN5UJ73H9i7LQzIBR3TjuJgUGNTFyRHk8"
|
|
|
|
# Database setup
|
|
DATABASE_NAME = "schedule.db"
|
|
|
|
def init_db():
|
|
"""Initialize the SQLite database and create tables if they don't exist."""
|
|
conn = sqlite3.connect(DATABASE_NAME)
|
|
cursor = conn.cursor()
|
|
|
|
# Create table for schedule entries
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS schedule (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
day TEXT NOT NULL,
|
|
period INTEGER NOT NULL,
|
|
subject TEXT NOT NULL,
|
|
class_name TEXT NOT NULL,
|
|
room TEXT NOT NULL,
|
|
UNIQUE(day, period)
|
|
)
|
|
''')
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
def add_schedule_entry(day, period, subject, class_name, room):
|
|
"""Add a new schedule entry to the database."""
|
|
conn = sqlite3.connect(DATABASE_NAME)
|
|
cursor = conn.cursor()
|
|
|
|
try:
|
|
cursor.execute('''
|
|
INSERT OR REPLACE INTO schedule (day, period, subject, class_name, room)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
''', (day, period, subject, class_name, room))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
return True
|
|
except sqlite3.Error as e:
|
|
print(f"Database error: {e}")
|
|
conn.close()
|
|
return False
|
|
|
|
def load_schedule_from_db():
|
|
"""Load schedule from the SQLite database."""
|
|
conn = sqlite3.connect(DATABASE_NAME)
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT day, period, subject, class_name, room FROM schedule ORDER BY day, period")
|
|
rows = cursor.fetchall()
|
|
|
|
conn.close()
|
|
|
|
# Group by day
|
|
schedule = {}
|
|
for day, period, subject, class_name, room in rows:
|
|
if day not in schedule:
|
|
schedule[day] = []
|
|
|
|
class_info = f"Subject: {subject} Class: {class_name} Room: {room}"
|
|
schedule[day].append((str(period), class_info))
|
|
|
|
return schedule
|
|
|
|
# Initialize the database
|
|
init_db()
|
|
|
|
# Map period numbers to times - Updated as requested
|
|
period_times = {
|
|
'1': ('09:00', '09:40'),
|
|
'2': ('10:00', '10:40'),
|
|
'3': ('11:00', '11:40'),
|
|
'4': ('11:50', '12:30'),
|
|
'5': ('12:40', '13:20'),
|
|
'6': ('13:30', '14:10'),
|
|
'7': ('14:20', '15:00'),
|
|
'8': ('15:20', '16:00'),
|
|
'9': ('16:15', '16:55'),
|
|
'10': ('17:05', '17:45'),
|
|
'11': ('17:55', '18:35'),
|
|
'12': ('18:45', '19:20'),
|
|
'13': ('19:20', '20:00')
|
|
}
|
|
|
|
# User states for tracking conversations
|
|
user_states = {} # Stores user conversation state
|
|
|
|
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Send welcome message when command /start is issued."""
|
|
await update.message.reply_text(
|
|
"🤖 Hello! I'm your enhanced class scheduler bot with database support!\n"
|
|
"Use /whereami to find your current class\n"
|
|
"Use /schedule to see today's full schedule\n"
|
|
"Use /tomorrow to see tomorrow's schedule\n"
|
|
"Use /add to add a new class to the schedule\n"
|
|
"Use /help for all commands"
|
|
)
|
|
|
|
|
|
async def where_am_i(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Tell user where they should be right now."""
|
|
# Reload schedule from DB to ensure latest data
|
|
schedule = load_schedule_from_db()
|
|
|
|
if not schedule:
|
|
await update.message.reply_text("❌ Schedule not loaded from database.")
|
|
return
|
|
|
|
now = datetime.datetime.now()
|
|
current_time = now.strftime("%H:%M")
|
|
current_day = now.strftime("%A")
|
|
|
|
await update.message.reply_text(f"📅 Today is {current_day}")
|
|
await update.message.reply_text(f"⏰ Current time: {current_time}")
|
|
|
|
# Check if we have schedule for today
|
|
if current_day not in schedule:
|
|
await update.message.reply_text("😊 No classes scheduled for today!")
|
|
return
|
|
|
|
# Find current class
|
|
found_class = False
|
|
for period_num, class_info in schedule[current_day]:
|
|
start_time, end_time = period_times[period_num]
|
|
|
|
if start_time <= current_time <= end_time:
|
|
await update.message.reply_text(f"🎯 You should be in: {class_info}")
|
|
found_class = True
|
|
break
|
|
|
|
if not found_class:
|
|
await update.message.reply_text("😊 No class right now! Free period.")
|
|
|
|
|
|
async def schedule(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Show the complete weekly schedule."""
|
|
# Reload schedule from DB to ensure latest data
|
|
schedule = load_schedule_from_db()
|
|
|
|
if not schedule:
|
|
await update.message.reply_text("❌ Schedule not loaded from database.")
|
|
return
|
|
|
|
schedule_text = "📚 Weekly Schedule:\n\n"
|
|
|
|
# Define the standard order of days in a week
|
|
days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
|
|
|
for day in days_of_week:
|
|
if day in schedule and schedule[day]: # Check if the day exists in the schedule and has classes
|
|
schedule_text += f"*{day}'s Schedule:*\n"
|
|
for period_num, class_info in schedule[day]:
|
|
start, end = period_times[period_num]
|
|
schedule_text += f" ⏰ {start}-{end}: {class_info}\n"
|
|
schedule_text += "\n"
|
|
else:
|
|
schedule_text += f"{day}: No classes scheduled\n\n"
|
|
|
|
await update.message.reply_text(schedule_text)
|
|
|
|
|
|
async def tomorrow(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Show tomorrow's schedule."""
|
|
# Reload schedule from DB to ensure latest data
|
|
schedule = load_schedule_from_db()
|
|
|
|
if not schedule:
|
|
await update.message.reply_text("❌ Schedule not loaded from database.")
|
|
return
|
|
|
|
tomorrow_date = datetime.datetime.now() + datetime.timedelta(days=1)
|
|
tomorrow_day = tomorrow_date.strftime("%A")
|
|
|
|
if tomorrow_day not in schedule or not schedule[tomorrow_day]:
|
|
await update.message.reply_text(f"😊 No classes scheduled for {tomorrow_day}!")
|
|
return
|
|
|
|
schedule_text = f"📚 {tomorrow_day}'s Schedule:\n\n"
|
|
for period_num, class_info in schedule[tomorrow_day]:
|
|
start, end = period_times[period_num]
|
|
schedule_text += f"⏰ {start}-{end}: {class_info}\n"
|
|
|
|
await update.message.reply_text(schedule_text)
|
|
|
|
|
|
async def add(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Start the process of adding a new schedule entry."""
|
|
user_id = update.effective_user.id
|
|
user_states[user_id] = {"step": "waiting_day"}
|
|
|
|
await update.message.reply_text(
|
|
"📅 Adding a new class to the schedule.\n"
|
|
"Please enter the day of the week (e.g., Monday, Tuesday, etc.):"
|
|
)
|
|
|
|
|
|
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Handle user messages during the add process."""
|
|
user_id = update.effective_user.id
|
|
|
|
if user_id not in user_states:
|
|
# Not in a conversation, ignore
|
|
return
|
|
|
|
state_info = user_states[user_id]
|
|
message_text = update.message.text.strip()
|
|
|
|
if state_info["step"] == "waiting_day":
|
|
# Validate day input
|
|
valid_days = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
|
|
if message_text.lower() not in valid_days:
|
|
await update.message.reply_text(
|
|
f"'{message_text}' is not a valid day of the week.\n"
|
|
"Please enter a valid day (e.g., Monday, Tuesday, etc.):"
|
|
)
|
|
return
|
|
|
|
state_info["day"] = message_text.capitalize()
|
|
state_info["step"] = "waiting_period"
|
|
|
|
await update.message.reply_text(
|
|
f"Got it! Day: {state_info['day']}\n"
|
|
"Now please enter the period number (1-13):"
|
|
)
|
|
|
|
elif state_info["step"] == "waiting_period":
|
|
try:
|
|
period = int(message_text)
|
|
if period < 1 or period > 13:
|
|
raise ValueError("Period must be between 1 and 13")
|
|
|
|
state_info["period"] = period
|
|
state_info["step"] = "waiting_subject"
|
|
|
|
await update.message.reply_text(
|
|
f"Got it! Period: {period}\n"
|
|
"Now please enter the subject name:"
|
|
)
|
|
except ValueError:
|
|
await update.message.reply_text(
|
|
f"'{message_text}' is not a valid period number.\n"
|
|
"Please enter a number between 1 and 13:"
|
|
)
|
|
|
|
elif state_info["step"] == "waiting_subject":
|
|
state_info["subject"] = message_text
|
|
state_info["step"] = "waiting_class"
|
|
|
|
await update.message.reply_text(
|
|
f"Got it! Subject: {message_text}\n"
|
|
"Now please enter the class name (e.g., 10ABC, 6A/6B, etc.):"
|
|
)
|
|
|
|
elif state_info["step"] == "waiting_class":
|
|
state_info["class_name"] = message_text
|
|
state_info["step"] = "waiting_room"
|
|
|
|
await update.message.reply_text(
|
|
f"Got it! Class: {message_text}\n"
|
|
"Finally, please enter the room number:"
|
|
)
|
|
|
|
elif state_info["step"] == "waiting_room":
|
|
state_info["room"] = message_text
|
|
|
|
# Add to database
|
|
success = add_schedule_entry(
|
|
state_info["day"],
|
|
state_info["period"],
|
|
state_info["subject"],
|
|
state_info["class_name"],
|
|
message_text
|
|
)
|
|
|
|
if success:
|
|
await update.message.reply_text(
|
|
f"✅ Successfully added to schedule!\n\n"
|
|
f"Day: {state_info['day']}\n"
|
|
f"Period: {state_info['period']}\n"
|
|
f"Subject: {state_info['subject']}\n"
|
|
f"Class: {state_info['class_name']}\n"
|
|
f"Room: {state_info['room']}"
|
|
)
|
|
else:
|
|
await update.message.reply_text(
|
|
f"❌ Failed to add to schedule. Please try again."
|
|
)
|
|
|
|
# Clean up user state
|
|
del user_states[user_id]
|
|
|
|
|
|
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Send help message with all commands."""
|
|
await update.message.reply_text(
|
|
"Available commands:\n"
|
|
"/start - Start the bot\n"
|
|
"/whereami - Find your current class\n"
|
|
"/schedule - Show today's full schedule\n"
|
|
"/tomorrow - Show tomorrow's schedule\n"
|
|
"/add - Add a new class to the schedule\n"
|
|
"/help - Show this help message"
|
|
)
|
|
|
|
|
|
def main():
|
|
"""Start the bot."""
|
|
# Create the Application
|
|
application = Application.builder().token(BOT_TOKEN).build()
|
|
|
|
# Add command handlers
|
|
application.add_handler(CommandHandler("start", start))
|
|
application.add_handler(CommandHandler("whereami", where_am_i))
|
|
application.add_handler(CommandHandler("schedule", schedule))
|
|
application.add_handler(CommandHandler("tomorrow", tomorrow))
|
|
application.add_handler(CommandHandler("add", add))
|
|
application.add_handler(CommandHandler("help", help_command))
|
|
|
|
# Add message handler for conversation flow
|
|
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
|
|
|
|
# Start the Bot
|
|
print("🤖 Enhanced scheduler bot with database support is running...")
|
|
print("📊 Database initialized successfully!")
|
|
print("Press Ctrl+C to stop the bot")
|
|
|
|
application.run_polling()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |