diff options
Diffstat (limited to 'bot.py')
-rw-r--r-- | bot.py | 108 |
1 files changed, 67 insertions, 41 deletions
@@ -18,20 +18,20 @@ if __version_info__ < (20, 0, 0, "alpha", 1): | |||
18 | f"{TG_VER} version of this example, " | 18 | f"{TG_VER} version of this example, " |
19 | f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html" | 19 | f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html" |
20 | ) | 20 | ) |
21 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ReplyKeyboardRemove | 21 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup |
22 | from telegram.ext import Application, CallbackQueryHandler, \ | 22 | from telegram.ext import Application, CallbackQueryHandler, \ |
23 | CommandHandler, ContextTypes, MessageHandler, filters, ConversationHandler, CallbackContext, JobQueue | 23 | CommandHandler, ContextTypes, MessageHandler, filters, ConversationHandler, CallbackContext |
24 | from config import BOT_TOKEN | 24 | from config import BOT_TOKEN |
25 | from foursquare.poi import query_poi | 25 | from foursquare.poi import query_poi |
26 | from dbstore.dbm_store import get_loc | 26 | from dbstore.dbm_store import get_loc |
27 | from toot import mastodon_client | 27 | from toot import mastodon_client |
28 | from typing import TypedDict, List, cast | 28 | from typing import TypedDict, List, cast |
29 | from telegram import Update, InputMediaVideo, InputMediaPhoto | 29 | from telegram import Update, ReplyKeyboardMarkup, KeyboardButton |
30 | 30 | ||
31 | scheduler = None | 31 | scheduler = None |
32 | PRIVACY, TOOT = map(chr, range(8, 10)) | 32 | PRIVACY, TOOT = map(chr, range(8, 10)) |
33 | 33 | ||
34 | WAIT_LOC, LOCATION, PHOTO, PROCESS_PHOTO, FINAL = range(5) | 34 | WAIT_LOC, LOCATION, PHOTO, PROCESS_PHOTO, FINAL, SETTING = range(6) |
35 | 35 | ||
36 | # Enable logging | 36 | # Enable logging |
37 | logging.basicConfig( | 37 | logging.basicConfig( |
@@ -39,6 +39,20 @@ logging.basicConfig( | |||
39 | ) | 39 | ) |
40 | logger = logging.getLogger(__name__) | 40 | logger = logging.getLogger(__name__) |
41 | 41 | ||
42 | MAIN_MENU = ReplyKeyboardMarkup([ | ||
43 | [telegram.KeyboardButton(text="/check in", request_location=True)], | ||
44 | [telegram.KeyboardButton(text="/cancel")], | ||
45 | [telegram.KeyboardButton(text="/setting")] | ||
46 | ]) | ||
47 | |||
48 | SKIP_MENU = ReplyKeyboardMarkup([[telegram.KeyboardButton(text="/skip")]]) | ||
49 | SETTING_MENU = ReplyKeyboardMarkup( | ||
50 | [ | ||
51 | [KeyboardButton(text="/tos")], | ||
52 | [telegram.KeyboardButton(text="/back")], | ||
53 | ] | ||
54 | ) | ||
55 | |||
42 | 56 | ||
43 | async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | 57 | async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: |
44 | hello = "Hello, this is `checkin.bot`. \n\n" \ | 58 | hello = "Hello, this is `checkin.bot`. \n\n" \ |
@@ -49,10 +63,7 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | |||
49 | "Start using this bot by sharing your location using Telegram context menu to it." | 63 | "Start using this bot by sharing your location using Telegram context menu to it." |
50 | 64 | ||
51 | await update.message.reply_text(hello, parse_mode=telegram.constants.ParseMode.MARKDOWN) | 65 | await update.message.reply_text(hello, parse_mode=telegram.constants.ParseMode.MARKDOWN) |
52 | await update.message.reply_text("Please choose", | 66 | await update.message.reply_text("Use bot keyboard to choose an action", reply_markup=MAIN_MENU) |
53 | reply_markup=telegram.ReplyKeyboardMarkup([ | ||
54 | [telegram.KeyboardButton(text="Check in", request_location=True)], | ||
55 | [telegram.KeyboardButton(text="Setting")]])) | ||
56 | 67 | ||
57 | return LOCATION | 68 | return LOCATION |
58 | 69 | ||
@@ -66,7 +77,7 @@ async def checkin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | |||
66 | ]) | 77 | ]) |
67 | 78 | ||
68 | reply_markup = InlineKeyboardMarkup(keyboard) | 79 | reply_markup = InlineKeyboardMarkup(keyboard) |
69 | await update.message.reply_text("Select a place", reply_markup=reply_markup) | 80 | await update.message.reply_text("Where are you?", reply_markup=reply_markup) |
70 | 81 | ||
71 | return WAIT_LOC | 82 | return WAIT_LOC |
72 | 83 | ||
@@ -94,32 +105,25 @@ async def process_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) - | |||
94 | await query.message.reply_text( | 105 | await query.message.reply_text( |
95 | text=f"Selected place: {poi['name']}, `{query.data}`\nPosted to Mastodon: {status['url']}", | 106 | text=f"Selected place: {poi['name']}, `{query.data}`\nPosted to Mastodon: {status['url']}", |
96 | parse_mode=telegram.constants.ParseMode.MARKDOWN, | 107 | parse_mode=telegram.constants.ParseMode.MARKDOWN, |
97 | reply_markup=telegram.ReplyKeyboardMarkup([ | 108 | reply_markup=MAIN_MENU |
98 | [telegram.KeyboardButton(text="Check in", request_location=True)], | ||
99 | [telegram.KeyboardButton(text="Setting")]]) | ||
100 | ) | 109 | ) |
101 | 110 | ||
102 | await query.message.reply_text("You can continue attaching photos, or press skip to continue", | 111 | await query.message.reply_text("You can continue attaching photos, or press skip to finish", reply_markup=SKIP_MENU) |
103 | reply_markup=telegram.ReplyKeyboardMarkup([ | ||
104 | [telegram.KeyboardButton(text="/skip")]])) | ||
105 | return PHOTO | 112 | return PHOTO |
106 | 113 | ||
107 | 114 | ||
108 | async def action(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | 115 | async def tos(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: |
109 | if update.message.text == "Check in": | 116 | await update.message.reply_text("TOS", reply_markup=MAIN_MENU) |
110 | await update.message.reply_text("Please share your location", | ||
111 | reply_markup=telegram.ReplyKeyboardRemove()) | ||
112 | elif update.message.text == "Setting": | ||
113 | await update.message.reply_text("Setting") | ||
114 | 117 | ||
115 | 118 | ||
116 | async def setting(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | 119 | async def setting(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: |
117 | keyboard = [[ | 120 | await update.message.reply_text("Setting", reply_markup=SETTING_MENU) |
118 | InlineKeyboardButton("Privacy", callback_data=PRIVACY), | 121 | return SETTING |
119 | ]] | ||
120 | 122 | ||
121 | reply_markup = InlineKeyboardMarkup(keyboard) | 123 | |
122 | await update.message.reply_text("Setting", reply_markup=reply_markup) | 124 | async def setting_process_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): |
125 | await update.message.reply_text("Setting Process Callback", reply_markup=SETTING_MENU) | ||
126 | return ConversationHandler.END | ||
123 | 127 | ||
124 | 128 | ||
125 | async def process_location(update: Update, context: ContextTypes.DEFAULT_TYPE): | 129 | async def process_location(update: Update, context: ContextTypes.DEFAULT_TYPE): |
@@ -154,12 +158,27 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No | |||
154 | await update.message.reply_text("Use /start to test this bot.") | 158 | await update.message.reply_text("Use /start to test this bot.") |
155 | 159 | ||
156 | 160 | ||
161 | async def setting_cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: | ||
162 | """Cancels and ends the conversation.""" | ||
163 | user = update.message.from_user | ||
164 | logger.info("User %s canceled the conversation.", user.first_name) | ||
165 | await update.message.reply_text( | ||
166 | text="Setting canceled.", | ||
167 | # "Bye! I hope we can talk again some day.", | ||
168 | reply_markup=MAIN_MENU | ||
169 | ) | ||
170 | |||
171 | return ConversationHandler.END | ||
172 | |||
173 | |||
157 | async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: | 174 | async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: |
158 | """Cancels and ends the conversation.""" | 175 | """Cancels and ends the conversation.""" |
159 | user = update.message.from_user | 176 | user = update.message.from_user |
160 | logger.info("User %s canceled the conversation.", user.first_name) | 177 | logger.info("User %s canceled the conversation.", user.first_name) |
161 | await update.message.reply_text( | 178 | await update.message.reply_text( |
162 | "Bye! I hope we can talk again some day.", reply_markup=ReplyKeyboardRemove() | 179 | text="Canceled.", |
180 | # "Bye! I hope we can talk again some day.", | ||
181 | reply_markup=MAIN_MENU | ||
163 | ) | 182 | ) |
164 | 183 | ||
165 | return ConversationHandler.END | 184 | return ConversationHandler.END |
@@ -197,9 +216,8 @@ async def media_group_sender(context: CallbackContext): | |||
197 | media_ids=media_id) | 216 | media_ids=media_id) |
198 | 217 | ||
199 | await context.bot.send_message(chat_id=chat_id, text="Done", | 218 | await context.bot.send_message(chat_id=chat_id, text="Done", |
200 | reply_markup=telegram.ReplyKeyboardMarkup([ | 219 | reply_markup=MAIN_MENU |
201 | [telegram.KeyboardButton(text="Check in", request_location=True)], | 220 | ) |
202 | [telegram.KeyboardButton(text="Setting")]])) | ||
203 | 221 | ||
204 | 222 | ||
205 | async def photo(update: Update, context: CallbackContext): | 223 | async def photo(update: Update, context: CallbackContext): |
@@ -225,9 +243,6 @@ async def photo(update: Update, context: CallbackContext): | |||
225 | if jobs: | 243 | if jobs: |
226 | jobs[0].data.append(msg_dict) | 244 | jobs[0].data.append(msg_dict) |
227 | else: | 245 | else: |
228 | # TODO | ||
229 | # media_group_sender won't end the callback context | ||
230 | # should add a job event listener | ||
231 | context.job_queue.run_once(callback=media_group_sender, when=5, data=[msg_dict], | 246 | context.job_queue.run_once(callback=media_group_sender, when=5, data=[msg_dict], |
232 | name=str(message.media_group_id)) | 247 | name=str(message.media_group_id)) |
233 | else: | 248 | else: |
@@ -243,17 +258,14 @@ async def photo(update: Update, context: CallbackContext): | |||
243 | media_ids=media["id"]) | 258 | media_ids=media["id"]) |
244 | 259 | ||
245 | await update.message.reply_text(text="Done", | 260 | await update.message.reply_text(text="Done", |
246 | reply_markup=telegram.ReplyKeyboardMarkup([ | 261 | reply_markup=MAIN_MENU |
247 | [telegram.KeyboardButton(text="Check in", request_location=True)], | 262 | ) |
248 | [telegram.KeyboardButton(text="Setting")]])) | ||
249 | 263 | ||
250 | 264 | ||
251 | async def skip_photo(update: Update, context: ContextTypes.DEFAULT_TYPE): | 265 | async def skip_photo(update: Update, context: ContextTypes.DEFAULT_TYPE): |
252 | print(context.user_data) | 266 | print(context.user_data) |
253 | await update.message.reply_text( | 267 | await update.message.reply_text( |
254 | text="Done.", reply_markup=telegram.ReplyKeyboardMarkup([ | 268 | text="Done.", reply_markup=MAIN_MENU |
255 | [telegram.KeyboardButton(text="Check in", request_location=True)], | ||
256 | [telegram.KeyboardButton(text="Setting")]]) | ||
257 | ) | 269 | ) |
258 | return ConversationHandler.END | 270 | return ConversationHandler.END |
259 | 271 | ||
@@ -261,7 +273,7 @@ async def skip_photo(update: Update, context: ContextTypes.DEFAULT_TYPE): | |||
261 | def main() -> None: | 273 | def main() -> None: |
262 | application = Application.builder().token(BOT_TOKEN).build() | 274 | application = Application.builder().token(BOT_TOKEN).build() |
263 | 275 | ||
264 | conv_handler = ConversationHandler( | 276 | checkin_handler = ConversationHandler( |
265 | entry_points=[ | 277 | entry_points=[ |
266 | CommandHandler("start", start), | 278 | CommandHandler("start", start), |
267 | MessageHandler(filters.LOCATION, checkin), | 279 | MessageHandler(filters.LOCATION, checkin), |
@@ -279,7 +291,21 @@ def main() -> None: | |||
279 | allow_reentry=True, | 291 | allow_reentry=True, |
280 | ) | 292 | ) |
281 | 293 | ||
282 | application.add_handler(conv_handler) | 294 | setting_conv_handler = ConversationHandler( |
295 | entry_points=[CommandHandler("setting", setting)], | ||
296 | states={ | ||
297 | SETTING: [ | ||
298 | CallbackQueryHandler(setting_process_callback), | ||
299 | ], | ||
300 | }, | ||
301 | fallbacks=[CommandHandler("back", setting_cancel)], | ||
302 | per_message=False, | ||
303 | allow_reentry=True, | ||
304 | ) | ||
305 | |||
306 | application.add_handler(CommandHandler("tos", tos)) | ||
307 | application.add_handler(setting_conv_handler, 2) | ||
308 | application.add_handler(checkin_handler, 1) | ||
283 | 309 | ||
284 | # Run the bot until the user presses Ctrl-C | 310 | # Run the bot until the user presses Ctrl-C |
285 | application.run_polling() | 311 | application.run_polling() |