2020-09-24 11:41:17 +02:00
|
|
|
import _pickle as pickle
|
|
|
|
import time
|
|
|
|
|
|
|
|
import schedule
|
|
|
|
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
|
|
|
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, CallbackQueryHandler, CallbackContext
|
|
|
|
from telegram.ext.filters import Filters
|
|
|
|
|
2020-09-24 19:34:29 +02:00
|
|
|
from bot import send_message, edit_message_and_delete_answer
|
2020-09-24 11:41:17 +02:00
|
|
|
from weather_openweathermap import City, get_city_by_name
|
|
|
|
|
|
|
|
users = {}
|
2020-09-24 19:34:29 +02:00
|
|
|
|
|
|
|
LIST, ADD_CITY, ADD_TIME, EDIT, EDIT_CITY, EDIT_TIME = range(6)
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Subscription(object):
|
|
|
|
time: time
|
|
|
|
city: City
|
|
|
|
chat_id: int
|
|
|
|
|
|
|
|
def __init__(self, chat_id: int, city: City):
|
|
|
|
self.chat_id = chat_id
|
|
|
|
self.city = city
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return f"{self.city.name} at {time.strftime('%H:%M', self.time)}"
|
|
|
|
|
|
|
|
def edit_time(self, edited_time: time):
|
|
|
|
self.time = edited_time
|
|
|
|
schedule_subscriptions()
|
|
|
|
save_users_to_file()
|
|
|
|
|
|
|
|
def edit_city(self, edited_city: City):
|
|
|
|
self.city = edited_city
|
|
|
|
schedule_subscriptions()
|
|
|
|
save_users_to_file()
|
|
|
|
|
|
|
|
|
|
|
|
class User(object):
|
|
|
|
chat_id: int
|
|
|
|
subs = []
|
|
|
|
|
|
|
|
def __init__(self, chat_id: int):
|
|
|
|
self.chat_id = chat_id
|
|
|
|
global users
|
|
|
|
users[self.chat_id] = self.subs
|
|
|
|
|
|
|
|
def __getstate__(self):
|
|
|
|
attributes = self.__dict__.copy()
|
|
|
|
attributes['subs'] = self.subs
|
|
|
|
for i in range(len(attributes['subs'])):
|
|
|
|
try:
|
|
|
|
del attributes['subs'][i].city.weather
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
return attributes
|
|
|
|
|
|
|
|
def __setstate__(self, state):
|
|
|
|
self.chat_id = state['chat_id']
|
|
|
|
self.subs = state['subs']
|
|
|
|
|
|
|
|
def add_subscription(self, subscription: Subscription):
|
|
|
|
self.subs.append(subscription)
|
|
|
|
global users
|
|
|
|
users[self.chat_id] = self
|
|
|
|
save_users_to_file()
|
|
|
|
schedule_subscriptions()
|
|
|
|
|
|
|
|
def del_subscription(self, idx: int):
|
|
|
|
del self.subs[idx]
|
|
|
|
save_users_to_file()
|
|
|
|
schedule_subscriptions()
|
|
|
|
|
|
|
|
|
|
|
|
def save_users_to_file():
|
|
|
|
global users
|
|
|
|
with open("users.pkl", 'wb') as users_file:
|
|
|
|
pickle.dump(users, users_file)
|
|
|
|
|
|
|
|
|
|
|
|
def load_users_from_file():
|
|
|
|
global users
|
|
|
|
try:
|
|
|
|
with open("users.pkl", 'rb') as users_file:
|
|
|
|
users = pickle.load(users_file)
|
|
|
|
schedule_subscriptions()
|
|
|
|
except FileNotFoundError:
|
|
|
|
pass
|
|
|
|
except EOFError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def schedule_subscriptions():
|
|
|
|
schedule.default_scheduler.clear()
|
|
|
|
for user in users.values():
|
|
|
|
for sub in user.subs:
|
2020-09-25 16:24:22 +02:00
|
|
|
schedule.default_scheduler.every().day.at(time.strftime("%H:%M", sub.time)).do(handle_subscription,
|
|
|
|
chat_id=user.chat_id,
|
|
|
|
sub=sub)
|
|
|
|
|
|
|
|
|
|
|
|
def handle_subscription(chat_id: int, sub: Subscription):
|
|
|
|
sub.city.query_weather()
|
|
|
|
send_message(chat_id=chat_id, message=sub.city.get_weather_str())
|
|
|
|
sub.city.weather.clear()
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
def push_callback(update: Update, context: CallbackContext):
|
|
|
|
global users
|
|
|
|
if update.effective_chat.id in users:
|
|
|
|
user = users[update.effective_chat.id]
|
|
|
|
else:
|
|
|
|
user = User(update.effective_chat.id)
|
|
|
|
users[update.effective_chat.id] = user
|
2020-09-24 19:34:29 +02:00
|
|
|
string = f"Hello, {update.effective_user.first_name}!\nYou have {len(user.subs)} subscriptions:\n"
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
button_list = []
|
|
|
|
for i, subscription in enumerate(user.subs):
|
|
|
|
button_list.append(
|
|
|
|
InlineKeyboardButton(text=f"{subscription.city.name} at {time.strftime('%H:%M', subscription.time)}",
|
|
|
|
callback_data=f"/push_edit {i}"))
|
|
|
|
button_list.append(InlineKeyboardButton(text="Add", callback_data="/push_add"))
|
2020-09-24 19:34:29 +02:00
|
|
|
button_list.append(InlineKeyboardButton(text="End", callback_data="/cancel"))
|
2020-09-24 11:41:17 +02:00
|
|
|
reply_markup = InlineKeyboardMarkup.from_column(button_list)
|
|
|
|
update.message.reply_text(string, reply_markup=reply_markup)
|
2020-09-24 19:34:29 +02:00
|
|
|
context.bot.delete_message(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id)
|
|
|
|
return LIST
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
def edit_sub_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
global users
|
2020-09-24 11:41:17 +02:00
|
|
|
user = users[update.effective_chat.id]
|
|
|
|
sub_idx = int(update.callback_query.data[11:])
|
|
|
|
sub = user.subs[sub_idx]
|
2020-09-24 19:34:29 +02:00
|
|
|
context.user_data['sub'] = sub
|
2020-09-24 11:41:17 +02:00
|
|
|
button_list = [[InlineKeyboardButton(text="City", callback_data="/push_edit_city"),
|
|
|
|
InlineKeyboardButton(text="Time", callback_data="/push_edit_time")],
|
2020-09-24 19:34:29 +02:00
|
|
|
[InlineKeyboardButton(text="Delete", callback_data=f"/push_edit_delete {sub_idx}"),
|
|
|
|
InlineKeyboardButton(text="Cancel", callback_data="/cancel")]]
|
2020-09-24 11:41:17 +02:00
|
|
|
reply_markup = InlineKeyboardMarkup(button_list)
|
2020-09-24 19:34:29 +02:00
|
|
|
update.callback_query.answer()
|
|
|
|
update.callback_query.edit_message_text(f"Change subscription {sub}.\nWhat do you want to change?",
|
|
|
|
reply_markup=reply_markup)
|
|
|
|
return EDIT
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
def edit_city_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
update.callback_query.answer()
|
|
|
|
update.callback_query.edit_message_text("Tell me the city you want information for:")
|
|
|
|
return EDIT_CITY
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
def edited_city_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
global users
|
2020-09-24 11:41:17 +02:00
|
|
|
user = users[update.effective_chat.id]
|
|
|
|
city_name = update.message.text
|
|
|
|
city = get_city_by_name(city_name)
|
|
|
|
if city.name == "none":
|
2020-09-24 19:34:29 +02:00
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message=f"The city {city_name} was not found! Try again")
|
2020-09-24 11:41:17 +02:00
|
|
|
return None
|
|
|
|
else:
|
2020-09-24 19:34:29 +02:00
|
|
|
context.user_data['sub'].edit_city(city)
|
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message=f"Subscription now is {context.user_data['sub']}")
|
|
|
|
|
|
|
|
del context.user_data['sub']
|
2020-09-24 11:41:17 +02:00
|
|
|
return ConversationHandler.END
|
|
|
|
|
|
|
|
|
|
|
|
def edit_time_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
update.callback_query.answer()
|
|
|
|
update.callback_query.edit_message_text("When do you want to receive updates?")
|
|
|
|
return EDIT_TIME
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
def edited_time_callback(update: Update, context: CallbackContext):
|
|
|
|
global users
|
|
|
|
user = users[update.effective_chat.id]
|
2020-09-24 19:34:29 +02:00
|
|
|
sub_in_edit = context.user_data['sub']
|
2020-09-24 11:41:17 +02:00
|
|
|
time_string = update.message.text
|
2020-09-24 19:34:29 +02:00
|
|
|
try:
|
|
|
|
if time_string.find(':') == -1:
|
|
|
|
sub_in_edit.edit_time(time.strptime(time_string, "%H"))
|
|
|
|
else:
|
|
|
|
sub_in_edit.edit_time(time.strptime(time_string, "%H:%M"))
|
|
|
|
except ValueError:
|
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message="This time was not recognized! Try again")
|
|
|
|
return None
|
|
|
|
del context.user_data['sub']
|
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message=f"Subscription now is {sub_in_edit}")
|
2020-09-24 11:41:17 +02:00
|
|
|
return ConversationHandler.END
|
|
|
|
|
|
|
|
|
|
|
|
def delete_subscription_callback(update: Update, context: CallbackContext):
|
|
|
|
global users
|
|
|
|
users[update.effective_chat.id].del_subscription(int(update.callback_query.data[18:]))
|
2020-09-24 19:34:29 +02:00
|
|
|
update.callback_query.answer()
|
|
|
|
update.callback_query.edit_message_text("Deleted")
|
2020-09-24 11:41:17 +02:00
|
|
|
schedule_subscriptions()
|
|
|
|
return ConversationHandler.END
|
|
|
|
|
|
|
|
|
|
|
|
def add_sub_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
update.callback_query.answer()
|
|
|
|
update.callback_query.edit_message_text("Add a new subscription.\nTell me the city you want information for:")
|
|
|
|
return ADD_CITY
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
def add_city_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
global users
|
2020-09-24 11:41:17 +02:00
|
|
|
user = users[update.effective_chat.id]
|
|
|
|
city_name = update.message.text
|
|
|
|
city = get_city_by_name(city_name)
|
|
|
|
if city.name == "none":
|
2020-09-24 19:34:29 +02:00
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message="This city was not found! Try again")
|
2020-09-24 11:41:17 +02:00
|
|
|
return None
|
|
|
|
else:
|
2020-09-24 19:34:29 +02:00
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message=f"I found {city.name}. When do you want to receive updates?")
|
|
|
|
context.user_data['sub'] = Subscription(user.chat_id, city)
|
|
|
|
return ADD_TIME
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
|
2020-09-24 19:34:29 +02:00
|
|
|
def add_time_callback(update: Update, context: CallbackContext):
|
|
|
|
global users
|
2020-09-24 11:41:17 +02:00
|
|
|
user = users[update.effective_chat.id]
|
2020-09-24 19:34:29 +02:00
|
|
|
sub_in_edit = context.user_data['sub']
|
2020-09-24 11:41:17 +02:00
|
|
|
time_string = update.message.text
|
2020-09-24 19:34:29 +02:00
|
|
|
try:
|
|
|
|
if time_string.find(':') == -1:
|
|
|
|
sub_in_edit.edit_time(time.strptime(time_string, "%H"))
|
|
|
|
else:
|
|
|
|
sub_in_edit.edit_time(time.strptime(time_string, "%H:%M"))
|
|
|
|
except ValueError:
|
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message="This time was not recognized! Try again")
|
|
|
|
return None
|
2020-09-24 11:41:17 +02:00
|
|
|
user.add_subscription(sub_in_edit)
|
2020-09-24 19:34:29 +02:00
|
|
|
edit_message_and_delete_answer(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id,
|
|
|
|
message=f"Subscription now is: {str(sub_in_edit)}")
|
|
|
|
del context.user_data['sub']
|
2020-09-24 11:41:17 +02:00
|
|
|
return ConversationHandler.END
|
|
|
|
|
|
|
|
|
|
|
|
def cancel_callback(update: Update, context: CallbackContext):
|
2020-09-24 19:34:29 +02:00
|
|
|
context.bot.delete_message(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id)
|
|
|
|
return ConversationHandler.END
|
|
|
|
|
|
|
|
|
|
|
|
def cancel_button_callback(update: Update, context: CallbackContext):
|
|
|
|
update.callback_query.answer()
|
|
|
|
update.effective_message.delete()
|
2020-09-24 11:41:17 +02:00
|
|
|
return ConversationHandler.END
|
|
|
|
|
|
|
|
|
|
|
|
def __init__() -> ConversationHandler:
|
|
|
|
load_users_from_file()
|
|
|
|
|
2020-09-24 19:34:29 +02:00
|
|
|
push_handler = CommandHandler(command=["push", "subs"], callback=push_callback)
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
edit_sub_handler = CallbackQueryHandler(callback=edit_sub_callback, pattern="^\/push_edit ")
|
|
|
|
edit_city_handler = CallbackQueryHandler(callback=edit_city_callback, pattern="^\/push_edit_city")
|
|
|
|
edited_city_handler = MessageHandler(callback=edited_city_callback, filters=Filters.text)
|
|
|
|
edit_time_handler = CallbackQueryHandler(callback=edit_time_callback, pattern="^\/push_edit_time")
|
|
|
|
edited_time_handler = MessageHandler(callback=edited_time_callback, filters=Filters.text)
|
|
|
|
delete_subscription_handler = CallbackQueryHandler(callback=delete_subscription_callback,
|
|
|
|
pattern="^\/push_edit_delete")
|
|
|
|
|
|
|
|
add_sub_handler = CallbackQueryHandler(callback=add_sub_callback, pattern="^\/push_add")
|
|
|
|
add_city_handler = MessageHandler(callback=add_city_callback, filters=Filters.text)
|
2020-09-24 19:34:29 +02:00
|
|
|
add_time_handler = MessageHandler(callback=add_time_callback, filters=Filters.text)
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
fallback_handler = CommandHandler(command="cancel", callback=cancel_callback)
|
2020-09-24 19:34:29 +02:00
|
|
|
fallback_callback_handler = CallbackQueryHandler(callback=cancel_button_callback, pattern="^\/cancel")
|
2020-09-24 11:41:17 +02:00
|
|
|
|
|
|
|
return ConversationHandler(entry_points=[push_handler],
|
2020-09-24 19:34:29 +02:00
|
|
|
states={LIST: [edit_sub_handler, add_sub_handler], ADD_CITY: [add_city_handler],
|
|
|
|
EDIT: [edit_city_handler, edit_time_handler, delete_subscription_handler],
|
|
|
|
EDIT_CITY: [edited_city_handler], EDIT_TIME: [edited_time_handler],
|
|
|
|
ADD_TIME: [add_time_handler]},
|
|
|
|
fallbacks=[fallback_handler, fallback_callback_handler])
|