Made conversation nicer
Messages now get deleted and deleted for a smoother experience. Other small changes: - States as constants - String formatting with f-string-literals
This commit is contained in:
parent
d6debf6a46
commit
4f403561ba
3 changed files with 112 additions and 76 deletions
23
bot.py
23
bot.py
|
@ -3,15 +3,16 @@ import threading
|
|||
import time
|
||||
|
||||
import schedule
|
||||
from telegram import InlineKeyboardMarkup, ParseMode
|
||||
from telegram.error import BadRequest
|
||||
from telegram.ext import Updater, CommandHandler, InlineQueryHandler, CallbackQueryHandler
|
||||
|
||||
from exceptions import *
|
||||
from push_information import __init__ as push_init
|
||||
from vvs import inline_station_search, handle_vvs, handle_multiple_stations_reply
|
||||
from weather_meteomedia import handle_meteomedia
|
||||
from weather_openweathermap import handle_weather
|
||||
from weather_openweathermap import __init__ as openweathermap_init
|
||||
from push_information import __init__ as push_init
|
||||
|
||||
from weather_openweathermap import handle_weather
|
||||
|
||||
token_file = open("token", "r")
|
||||
updater = Updater(token=token_file.read(), use_context=True)
|
||||
|
@ -23,7 +24,21 @@ logging.basicConfig(format='%(acstime)s - %(name)s - %(levelname)s - %(message)s
|
|||
|
||||
|
||||
def send_message(chat_id: int, message: str):
|
||||
dispatcher.bot.send_message(chat_id=chat_id, text=message, disable_notification=True, parse_mode="Markdown")
|
||||
dispatcher.bot.send_message(chat_id=chat_id, text=message, disable_notification=True, parse_mode=ParseMode.MARKDOWN)
|
||||
|
||||
|
||||
def edit_message_and_delete_answer(chat_id: int, message_id: int, message: str,
|
||||
reply_markup: InlineKeyboardMarkup = None):
|
||||
dispatcher.bot.delete_message(chat_id=chat_id, message_id=message_id)
|
||||
try:
|
||||
dispatcher.bot.edit_message_text(chat_id=chat_id, message_id=message_id - 1, text=message,
|
||||
reply_markup=reply_markup)
|
||||
except BadRequest:
|
||||
try:
|
||||
dispatcher.bot.edit_message_text(chat_id=chat_id, message_id=message_id - 2, text=message,
|
||||
reply_markup=reply_markup)
|
||||
except BadRequest:
|
||||
pass
|
||||
|
||||
|
||||
cease_continuous_run = threading.Event()
|
||||
|
|
|
@ -6,11 +6,12 @@ from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
|||
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, CallbackQueryHandler, CallbackContext
|
||||
from telegram.ext.filters import Filters
|
||||
|
||||
from bot import send_message
|
||||
from bot import send_message, edit_message_and_delete_answer
|
||||
from weather_openweathermap import City, get_city_by_name
|
||||
|
||||
users = {}
|
||||
subs_in_edit = {}
|
||||
|
||||
LIST, ADD_CITY, ADD_TIME, EDIT, EDIT_CITY, EDIT_TIME = range(6)
|
||||
|
||||
|
||||
class Subscription(object):
|
||||
|
@ -107,8 +108,7 @@ def push_callback(update: Update, context: CallbackContext):
|
|||
else:
|
||||
user = User(update.effective_chat.id)
|
||||
users[update.effective_chat.id] = user
|
||||
string = f"Hello, {update.effective_user.first_name}!\n"
|
||||
string += f"You have {len(user.subs)} subscriptions:\n"
|
||||
string = f"Hello, {update.effective_user.first_name}!\nYou have {len(user.subs)} subscriptions:\n"
|
||||
|
||||
button_list = []
|
||||
for i, subscription in enumerate(user.subs):
|
||||
|
@ -116,116 +116,147 @@ def push_callback(update: Update, context: CallbackContext):
|
|||
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"))
|
||||
button_list.append(InlineKeyboardButton(text="End", callback_data="/cancel"))
|
||||
reply_markup = InlineKeyboardMarkup.from_column(button_list)
|
||||
update.message.reply_text(string, reply_markup=reply_markup)
|
||||
return "list"
|
||||
context.bot.delete_message(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id)
|
||||
return LIST
|
||||
|
||||
|
||||
def edit_sub_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
global users
|
||||
user = users[update.effective_chat.id]
|
||||
sub_idx = int(update.callback_query.data[11:])
|
||||
sub = user.subs[sub_idx]
|
||||
subs_in_edit[update.effective_chat.id] = sub
|
||||
context.user_data['sub'] = sub
|
||||
button_list = [[InlineKeyboardButton(text="City", callback_data="/push_edit_city"),
|
||||
InlineKeyboardButton(text="Time", callback_data="/push_edit_time")],
|
||||
[InlineKeyboardButton(text="Delete", callback_data=f"/push_edit_delete {sub_idx}")]]
|
||||
[InlineKeyboardButton(text="Delete", callback_data=f"/push_edit_delete {sub_idx}"),
|
||||
InlineKeyboardButton(text="Cancel", callback_data="/cancel")]]
|
||||
reply_markup = InlineKeyboardMarkup(button_list)
|
||||
update.effective_chat.send_message("Change subscription.\nWhat do you want to change?", reply_markup=reply_markup)
|
||||
return "edit"
|
||||
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
|
||||
|
||||
|
||||
def edit_city_callback(update: Update, context: CallbackContext):
|
||||
update.effective_chat.send_message("Tell me the city you want information for:")
|
||||
return "edit_city"
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text("Tell me the city you want information for:")
|
||||
return EDIT_CITY
|
||||
|
||||
|
||||
def edited_city_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
global users
|
||||
user = users[update.effective_chat.id]
|
||||
city_name = update.message.text
|
||||
city = get_city_by_name(city_name)
|
||||
if city.name == "none":
|
||||
update.message.reply_text("This city was not found! Try again")
|
||||
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")
|
||||
return None
|
||||
else:
|
||||
subs_in_edit[user.chat_id].edit_city(city)
|
||||
update.message.reply_text(f"City changed to {city.name}.")
|
||||
del subs_in_edit[update.effective_chat.id]
|
||||
update.message.reply_text(f"Subscription now is {subs_in_edit[user.chat_id]}")
|
||||
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']
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def edit_time_callback(update: Update, context: CallbackContext):
|
||||
update.effective_chat.send_message("When do you want to receive updates?")
|
||||
return "edit_time"
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text("When do you want to receive updates?")
|
||||
return EDIT_TIME
|
||||
|
||||
|
||||
def edited_time_callback(update: Update, context: CallbackContext):
|
||||
global users
|
||||
user = users[update.effective_chat.id]
|
||||
sub_in_edit = subs_in_edit[user.chat_id]
|
||||
sub_in_edit = context.user_data['sub']
|
||||
time_string = update.message.text
|
||||
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"))
|
||||
del subs_in_edit[user.chat_id]
|
||||
update.message.reply_text(f"Subscription now is {sub_in_edit}")
|
||||
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}")
|
||||
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:]))
|
||||
update.effective_chat.send_message("Deleted")
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text("Deleted")
|
||||
schedule_subscriptions()
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def add_sub_callback(update: Update, context: CallbackContext):
|
||||
update.effective_chat.send_message("Add a new subscription.\nTell me the city you want information for:")
|
||||
return "add_city"
|
||||
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
|
||||
|
||||
|
||||
def add_city_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
global users
|
||||
user = users[update.effective_chat.id]
|
||||
city_name = update.message.text
|
||||
city = get_city_by_name(city_name)
|
||||
if city.name == "none":
|
||||
update.message.reply_text("This city was not found! Try again")
|
||||
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")
|
||||
return None
|
||||
else:
|
||||
update.message.reply_text(f"I found {city.name}. When do you want to receive updates?")
|
||||
subs_in_edit[user.chat_id] = Subscription(user.chat_id, city)
|
||||
return "time"
|
||||
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
|
||||
|
||||
|
||||
def time_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
def add_time_callback(update: Update, context: CallbackContext):
|
||||
global users
|
||||
user = users[update.effective_chat.id]
|
||||
sub_in_edit = subs_in_edit[update.effective_chat.id]
|
||||
sub_in_edit = context.user_data['sub']
|
||||
time_string = update.message.text
|
||||
try:
|
||||
if time_string.find(':') == -1:
|
||||
sub_in_edit.time = time.strptime(time_string, "%H")
|
||||
sub_in_edit.edit_time(time.strptime(time_string, "%H"))
|
||||
else:
|
||||
sub_in_edit.time = time.strptime(time_string, "%H:%M")
|
||||
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
|
||||
user.add_subscription(sub_in_edit)
|
||||
update.message.reply_text(f"Subscription now is: {str(sub_in_edit)}")
|
||||
del subs_in_edit[update.effective_chat.id]
|
||||
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']
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def cancel_callback(update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Timeout")
|
||||
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()
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def __init__() -> ConversationHandler:
|
||||
load_users_from_file()
|
||||
|
||||
push_handler = CommandHandler(command="push", callback=push_callback)
|
||||
push_handler = CommandHandler(command=["push", "subs"], callback=push_callback)
|
||||
|
||||
edit_sub_handler = CallbackQueryHandler(callback=edit_sub_callback, pattern="^\/push_edit ")
|
||||
edit_city_handler = CallbackQueryHandler(callback=edit_city_callback, pattern="^\/push_edit_city")
|
||||
|
@ -237,14 +268,14 @@ def __init__() -> ConversationHandler:
|
|||
|
||||
add_sub_handler = CallbackQueryHandler(callback=add_sub_callback, pattern="^\/push_add")
|
||||
add_city_handler = MessageHandler(callback=add_city_callback, filters=Filters.text)
|
||||
|
||||
time_handler = MessageHandler(callback=time_callback, filters=Filters.text)
|
||||
add_time_handler = MessageHandler(callback=add_time_callback, filters=Filters.text)
|
||||
|
||||
fallback_handler = CommandHandler(command="cancel", callback=cancel_callback)
|
||||
fallback_callback_handler = CallbackQueryHandler(callback=cancel_button_callback, pattern="^\/cancel")
|
||||
|
||||
return ConversationHandler(entry_points=[push_handler],
|
||||
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],
|
||||
"time": [time_handler]},
|
||||
fallbacks=[fallback_handler], conversation_timeout=10)
|
||||
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])
|
||||
|
|
|
@ -2,6 +2,7 @@ import json
|
|||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
from telegram import ParseMode
|
||||
|
||||
from exceptions import ServerCommunicationError, NoArgError, WeatherStationNotFoundError
|
||||
|
||||
|
@ -38,16 +39,11 @@ class HourlyWeather:
|
|||
self.description = json_data['weather'][0]['description']
|
||||
|
||||
def __str__(self):
|
||||
string = ""
|
||||
string += "*{time}*: {main} | {temperature:.0f}°C 🧑: {feels_like:.0f}°C" \
|
||||
.format(time=self.time.strftime("%Hh"),
|
||||
main=self.main,
|
||||
temperature=self.temperature,
|
||||
feels_like=self.feels_like)
|
||||
string = f"*{self.time.strftime('%Hh')}*: {self.main} | {self.temperature:.0f}°C 🧑: {self.feels_like:.0f}°C"
|
||||
if self.probability_of_precipitation != 0:
|
||||
string += " ☔: {pop:.0f}% {rain}mm".format(pop=100 * self.probability_of_precipitation, rain=self.rain)
|
||||
string += f" ☔: {100 * self.probability_of_precipitation:.0f}% {self.rain}mm"
|
||||
|
||||
string += " 💨{wind_speed:.1f}km/h".format(wind_speed=3.6 * self.wind_speed)
|
||||
string += f" 💨{3.6 * self.wind_speed:.1f}km/h"
|
||||
return string
|
||||
|
||||
|
||||
|
@ -75,17 +71,11 @@ class DailyWeather:
|
|||
self.description = json_data['weather'][0]['description']
|
||||
|
||||
def __str__(self):
|
||||
string = ""
|
||||
string += "*{time}*: {main} | {min}°C - {day}°C - {max}°C 🧑: {feels_like_day:.0f}°C" \
|
||||
.format(time=self.time.strftime("%d"),
|
||||
main=self.main,
|
||||
min=self.temp['min'],
|
||||
day=self.temp['day'],
|
||||
max=self.temp['max'],
|
||||
feels_like_day=self.feels_like)
|
||||
string = f"*{self.time.strftime('%d')}*: {self.main} | {self.temp['min']:.0f}°C - {self.temp['day']:.0f}°C" \
|
||||
f" - {self.temp['max']:.0f}°C 🧑: {self.feels_like:.0f}°C"
|
||||
if self.probability_of_precipitation != 0:
|
||||
string += " ☔: {pop:.0f}% {rain}mm".format(pop=100 * self.probability_of_precipitation, rain=self.rain)
|
||||
string += " 💨: {wind_speed:.1f}km/h".format(wind_speed=3.6 * self.wind_speed)
|
||||
string += f" ☔: {100 * self.probability_of_precipitation:.0f}% {self.rain}mm"
|
||||
string += f" 💨: {3.6 * self.wind_speed:.1f}km/h"
|
||||
return string
|
||||
|
||||
|
||||
|
@ -194,6 +184,6 @@ def handle_weather(update, context):
|
|||
if requested_city.name == "none":
|
||||
raise WeatherStationNotFoundError
|
||||
requested_city.query_weather()
|
||||
update.message.reply_text(str(requested_city.weather), disable_notification=True, parse_mode="Markdown")
|
||||
update.message.reply_text(str(requested_city.weather), disable_notification=True, parse_mode=ParseMode.MARKDOWN)
|
||||
|
||||
requested_city.weather.clear()
|
||||
|
|
Loading…
Reference in a new issue