aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bot.py278
-rw-r--r--config.py2
-rw-r--r--prompt/string.py12
3 files changed, 104 insertions, 188 deletions
diff --git a/bot.py b/bot.py
index c7a3180..f238e75 100644
--- a/bot.py
+++ b/bot.py
@@ -1,12 +1,7 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2# pylint: disable=unused-argument, wrong-import-position
3# This program is dedicated to the public domain under the CC0 license.
4 2
5import logging
6import io
7import telegram.constants 3import telegram.constants
8from telegram import __version__ as TG_VER 4from telegram import __version__ as TG_VER
9from pprint import pprint
10 5
11try: 6try:
12 from telegram import __version_info__ 7 from telegram import __version_info__
@@ -20,46 +15,44 @@ if __version_info__ < (20, 0, 0, "alpha", 1):
20 f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html" 15 f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
21 ) 16 )
22 17
18import logging
19from pprint import pprint
20import io
23from foursquare.poi import OSM_ENDPOINT 21from foursquare.poi import OSM_ENDPOINT
24from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ReplyKeyboardMarkup, KeyboardButton 22from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ReplyKeyboardMarkup, KeyboardButton
25from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, MessageHandler, filters, \ 23from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, MessageHandler, filters, \
26 ConversationHandler, CallbackContext 24 ConversationHandler, CallbackContext
27from config import BOT_TOKEN 25from config import BOT_TOKEN, MEDIA_GROUP_TIMEOUT
28from foursquare.poi import query_poi 26from foursquare.poi import query_poi
29from dbstore.dbm_store import get_loc 27from dbstore.dbm_store import get_loc
30from toot import mastodon_client 28from toot import mastodon_client
31from typing import TypedDict, List, cast 29from typing import TypedDict, List, cast
30from prompt.string import *
32 31
33scheduler = None
34PRIVACY, TOOT = map(chr, range(8, 10))
35
36WAIT_LOC, LOCATION, LOCATION_SEARCH, PHOTO, PROCESS_PHOTO, COMMENT, SETTING = range(7)
37 32
38# Enable logging
39logging.basicConfig( 33logging.basicConfig(
40 format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO 34 format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
41) 35)
42logger = logging.getLogger(__name__) 36logger = logging.getLogger(__name__)
43 37
38WAIT_LOCATION, LOCATION_SEARCH_KEYWORD, LOCATION_CONFIRMATION, ADD_MEDIA, ADD_COMMENT = range(5)
39
44MAIN_MENU = ReplyKeyboardMarkup([ 40MAIN_MENU = ReplyKeyboardMarkup([
45 [KeyboardButton(text="Check-in here", request_location=True)], 41 [KeyboardButton(text="Check-in here", request_location=True)],
46 # [KeyboardButton(text="/cancel")],
47 # [KeyboardButton(text="/setting")]
48]) 42])
49 43
50SKIP_LOCATION_SEARCH = "skip_location_search" 44SKIP_LOCATION_SEARCH = CALLBACK_SKIP
51 45INLINE_SKIP_MENU = InlineKeyboardMarkup([
52SKIP_MENU = InlineKeyboardMarkup([
53 [telegram.InlineKeyboardButton("Skip", callback_data=SKIP_LOCATION_SEARCH)] 46 [telegram.InlineKeyboardButton("Skip", callback_data=SKIP_LOCATION_SEARCH)]
54]) 47])
55 48
56 49
57# SETTING_MENU = InlineKeyboardMarkup( 50class MsgDict(TypedDict):
58# [ 51 media_id: str
59# [InlineKeyboardButton(text="/tos")], 52 caption: str
60# [InlineKeyboardButton(text="/back")], 53 status_id: int
61# ] 54 content: str
62# ) 55 chat_id: int
63 56
64 57
65async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 58async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
@@ -71,13 +64,12 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
71 "Start using this bot by sharing your location using Telegram context menu to it." 64 "Start using this bot by sharing your location using Telegram context menu to it."
72 65
73 await update.message.reply_text(hello, parse_mode=telegram.constants.ParseMode.MARKDOWN) 66 await update.message.reply_text(hello, parse_mode=telegram.constants.ParseMode.MARKDOWN)
74 await update.message.reply_text("Use bot keyboard to choose an action", reply_markup=MAIN_MENU) 67 await update.message.reply_text(PROMPT_CHOOSE_ACTION, reply_markup=MAIN_MENU)
75 68
76 return LOCATION 69 return WAIT_LOCATION
77 70
78 71
79async def checkin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 72async def callback_location_sharing(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
80 pprint(update.message.location)
81 if update.message.venue is not None: 73 if update.message.venue is not None:
82 fsq_id = update.message.venue.foursquare_id 74 fsq_id = update.message.venue.foursquare_id
83 title = update.message.venue.title 75 title = update.message.venue.title
@@ -104,28 +96,22 @@ async def checkin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
104 parse_mode=telegram.constants.ParseMode.MARKDOWN, 96 parse_mode=telegram.constants.ParseMode.MARKDOWN,
105 ) 97 )
106 98
107 prompt_attach_comment_msg = await update.message.reply_text( 99 prompt_attach_comment_msg = await update.message.reply_text(PROMPT_ADD_COMMENT, reply_markup=INLINE_SKIP_MENU)
108 "You can continue adding comments, or press skip to finish", reply_markup=SKIP_MENU) 100 context.user_data[PROMPT_ADD_COMMENT] = prompt_attach_comment_msg.message_id
109 context.user_data["prompt_attach_comment_msg_id"] = prompt_attach_comment_msg.message_id
110 101
111 return COMMENT 102 return ADD_COMMENT
112 else: 103 else:
113 context.user_data["latitude"] = update.message.location.latitude 104 context.user_data["latitude"] = update.message.location.latitude
114 context.user_data["longitude"] = update.message.location.longitude 105 context.user_data["longitude"] = update.message.location.longitude
115 106
116 await update.message.reply_text("Searching...", reply_markup=telegram.ReplyKeyboardRemove()) 107 await update.message.reply_text("Searching...", reply_markup=telegram.ReplyKeyboardRemove())
117 prompt_msg = await update.message.reply_text("You can input location search keywords or press skip", 108 prompt_msg = await update.message.reply_text(PROMPT_LOCATION_KEYWORD, reply_markup=INLINE_SKIP_MENU)
118 reply_markup=SKIP_MENU)
119 109
120 context.user_data["prompt_msg_id"] = prompt_msg.message_id 110 context.user_data[PROMPT_LOCATION_KEYWORD] = prompt_msg.message_id
121 return LOCATION_SEARCH 111 return LOCATION_SEARCH_KEYWORD
122 112
123 113
124async def manual_location_process_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 114async def callback_manual_location(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
125 # query = update.callback_query
126 # await query.answer()
127 # await query.delete_message()
128
129 loc = update.effective_message.text 115 loc = update.effective_message.text
130 osm_url = OSM_ENDPOINT.format(context.user_data["latitude"], context.user_data["longitude"]) 116 osm_url = OSM_ENDPOINT.format(context.user_data["latitude"], context.user_data["longitude"])
131 media_id = [] 117 media_id = []
@@ -143,22 +129,19 @@ async def manual_location_process_callback(update: Update, context: ContextTypes
143 await update.message.reply_text( 129 await update.message.reply_text(
144 text=f"Manually selected place: {loc}, \nPosted to Mastodon: {status['url']}", 130 text=f"Manually selected place: {loc}, \nPosted to Mastodon: {status['url']}",
145 parse_mode=telegram.constants.ParseMode.MARKDOWN, 131 parse_mode=telegram.constants.ParseMode.MARKDOWN,
146 # reply_markup=MAIN_MENU
147 ) 132 )
148 133
149 prompt_attach_comment_msg = await update.message.reply_text( 134 prompt_attach_comment_msg = await update.message.reply_text(PROMPT_ADD_COMMENT, reply_markup=INLINE_SKIP_MENU)
150 "You can continue adding comments, or press skip to finish", reply_markup=SKIP_MENU) 135 context.user_data[PROMPT_ADD_COMMENT] = prompt_attach_comment_msg.message_id
151 context.user_data["prompt_attach_comment_msg_id"] = prompt_attach_comment_msg.message_id
152 136
153 return COMMENT 137 return ADD_COMMENT
154 138
155 139
156async def process_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 140async def callback_location_confirmation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
157 print("process_callback")
158 query = update.callback_query 141 query = update.callback_query
159 await query.answer() 142 await query.answer()
160 print(query.data)
161 context.user_data["fsq_id"] = query.data 143 context.user_data["fsq_id"] = query.data
144
162 await query.delete_message() 145 await query.delete_message()
163 146
164 poi = get_loc(context.user_data["fsq_id"]) 147 poi = get_loc(context.user_data["fsq_id"])
@@ -177,18 +160,16 @@ async def process_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
177 await query.message.reply_text( 160 await query.message.reply_text(
178 text=f"Selected place: {poi['name']}, `{query.data}`\nPosted to Mastodon: {status['url']}", 161 text=f"Selected place: {poi['name']}, `{query.data}`\nPosted to Mastodon: {status['url']}",
179 parse_mode=telegram.constants.ParseMode.MARKDOWN, 162 parse_mode=telegram.constants.ParseMode.MARKDOWN,
180 # reply_markup=MAIN_MENU
181 ) 163 )
182 164
183 prompt_attach_comment_msg = await query.message.reply_text( 165 prompt_attach_comment_msg = await query.message.reply_text(PROMPT_ADD_COMMENT, reply_markup=INLINE_SKIP_MENU)
184 "You can continue adding comments, or press skip to finish", reply_markup=SKIP_MENU) 166 context.user_data[PROMPT_ADD_COMMENT] = prompt_attach_comment_msg.message_id
185 context.user_data["prompt_attach_comment_msg_id"] = prompt_attach_comment_msg.message_id
186 167
187 return COMMENT 168 return ADD_COMMENT
188 169
189 170
190async def location_search_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 171async def callback_location_keyword_search(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
191 await context.bot.delete_message(update.effective_chat.id, context.user_data["prompt_msg_id"]) 172 await context.bot.delete_message(update.effective_chat.id, context.user_data[PROMPT_LOCATION_KEYWORD])
192 173
193 location_search = update.effective_message.text 174 location_search = update.effective_message.text
194 latitude = context.user_data["latitude"] 175 latitude = context.user_data["latitude"]
@@ -199,26 +180,25 @@ async def location_search_callback(update: Update, context: ContextTypes.DEFAULT
199 if len(poi_result) == 0: 180 if len(poi_result) == 0:
200 poi_result = query_poi("", latitude, longitude) 181 poi_result = query_poi("", latitude, longitude)
201 182
202 # for poi in poi_result: 183 for poi in poi_result:
203 # keyboard.append([ 184 keyboard.append([
204 # InlineKeyboardButton(poi["name"], callback_data=poi["fsq_id"]), 185 InlineKeyboardButton(poi["name"], callback_data=poi["fsq_id"]),
205 # ]) 186 ])
206 187
207 if len(keyboard) == 0: 188 if len(keyboard) == 0:
208 await update.message.reply_text("No nearby places found. You can input location name manually") 189 await update.message.reply_text(PROMPT_NO_NEARBY_POI)
209 return WAIT_LOC 190 return LOCATION_CONFIRMATION
210 else: 191 else:
211 reply_markup = InlineKeyboardMarkup(keyboard) 192 reply_markup = InlineKeyboardMarkup(keyboard)
212 context.user_data["location_search"] = location_search 193 context.user_data["location_search"] = location_search
213 await update.message.reply_text("Where are you? ", reply_markup=reply_markup) 194 await update.message.reply_text(PROMPT_CHOOSE_POI_FROM_LIST, reply_markup=reply_markup)
214 195
215 return WAIT_LOC 196 return LOCATION_CONFIRMATION
216 197
217 198
218async def skip_location_search(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 199async def callback_skip_location_keyword(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
219 query = update.callback_query 200 query = update.callback_query
220 await query.answer() 201 await query.answer()
221 print("skip: ", query.data)
222 202
223 await query.message.delete() 203 await query.message.delete()
224 latitude = context.user_data["latitude"] 204 latitude = context.user_data["latitude"]
@@ -232,13 +212,13 @@ async def skip_location_search(update: Update, context: ContextTypes.DEFAULT_TYP
232 ]) 212 ])
233 213
234 reply_markup = InlineKeyboardMarkup(keyboard) 214 reply_markup = InlineKeyboardMarkup(keyboard)
235 await query.message.reply_text("Where are you? ", reply_markup=reply_markup) 215 await query.message.reply_text(PROMPT_CHOOSE_POI_FROM_LIST, reply_markup=reply_markup)
236 216
237 return WAIT_LOC 217 return LOCATION_CONFIRMATION
238 218
239 219
240async def comment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 220async def callback_add_comment(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
241 await context.bot.delete_message(update.effective_chat.id, context.user_data["prompt_attach_comment_msg_id"]) 221 await context.bot.delete_message(update.effective_chat.id, context.user_data[PROMPT_ADD_COMMENT])
242 comment = update.effective_message.text 222 comment = update.effective_message.text
243 223
244 mastodon_client.status_update( 224 mastodon_client.status_update(
@@ -246,110 +226,39 @@ async def comment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
246 id=context.user_data["status_id"]) 226 id=context.user_data["status_id"])
247 227
248 context.user_data["status_content"] = f"{comment} " + context.user_data["status_content"] 228 context.user_data["status_content"] = f"{comment} " + context.user_data["status_content"]
249 prompt_attach_photo_msg = await update.message.reply_text( 229 prompt_attach_photo_msg = await update.message.reply_text(PROMPT_ADD_MEDIA, reply_markup=INLINE_SKIP_MENU)
250 "You can continue attaching photos, or press skip to finish", reply_markup=SKIP_MENU) 230 context.user_data[PROMPT_ADD_MEDIA] = prompt_attach_photo_msg.message_id
251 context.user_data["prompt_attach_photo_msg_id"] = prompt_attach_photo_msg.message_id
252
253 return PHOTO
254
255
256async def skip_comment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
257 await context.bot.delete_message(update.effective_chat.id, context.user_data["prompt_attach_comment_msg_id"])
258 prompt_attach_photo_msg = await update.message.reply_text(
259 "You can continue attaching photos, or press skip to finish", reply_markup=SKIP_MENU)
260 context.user_data["prompt_attach_photo_msg_id"] = prompt_attach_photo_msg.message_id
261 return PHOTO
262
263
264# async def tos(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
265# await update.message.reply_text("TOS", reply_markup=MAIN_MENU)
266
267
268# async def setting(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
269# await update.message.reply_text("Setting", reply_markup=SETTING_MENU)
270# return SETTING
271
272
273# async def setting_process_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
274# await update.message.reply_text("Setting Process Callback", reply_markup=SETTING_MENU)
275# return ConversationHandler.END
276
277
278# async def process_location(update: Update, context: ContextTypes.DEFAULT_TYPE):
279# await update.message.reply_chat_action(telegram.constants.ChatAction.TYPING)
280#
281# fsq_id = context.user_data["fsq_id"]
282# poi = get_loc(context.user_data["fsq_id"])
283# media_id = []
284#
285# if context.user_data.get("photo") is not None:
286# media = mastodon_client.media_post(context.user_data.get("photo"), mime_type="image/jpeg")
287# media_id = [media["id"]]
288# # else:
289# # photo_url = get_poi_top_photo(context.user_data["fsq_id"])
290# # if photo_url is not None:
291# # with urllib.request.urlopen(photo_url) as response:
292# # data = response.read()
293# # media = mastodon_client.media_post(data, mime_type="image/jpeg")
294# # media_id = [media["id"]]
295#
296# mastodon_client.status_post(
297# f"I'm at {poi['name']} in {poi['locality']}, {poi['region']}, {poi['osm_url']}",
298# visibility="private",
299# media_ids=media_id)
300#
301# await update.message.delete()
302# return ConversationHandler.END
303 231
232 return ADD_MEDIA
304 233
305async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
306 """Displays info on how to use the bot."""
307 await update.message.reply_text("Use /start to test this bot.")
308 234
235async def callback_skip_comment(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
236 await context.bot.delete_message(update.effective_chat.id, context.user_data[PROMPT_ADD_COMMENT])
237 prompt_attach_photo_msg = await update.message.reply_text(PROMPT_ADD_MEDIA, reply_markup=INLINE_SKIP_MENU)
238 context.user_data[PROMPT_ADD_MEDIA] = prompt_attach_photo_msg.message_id
239 return ADD_MEDIA
309 240
310# async def setting_cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 241
311# """Cancels and ends the conversation.""" 242async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
312# user = update.message.from_user 243 await update.message.reply_text(PROMPT_HELP)
313# logger.info("User %s canceled the conversation.", user.first_name)
314# await update.message.reply_text(
315# text="Setting canceled.",
316# # "Bye! I hope we can talk again some day.",
317# reply_markup=MAIN_MENU
318# )
319#
320# return ConversationHandler.END
321 244
322 245
323async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 246async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
324 """Cancels and ends the conversation.""" 247 await update.message.reply_text(text=PROMPT_CANCELED, reply_markup=MAIN_MENU)
325 user = update.message.from_user
326 logger.info("User %s canceled the conversation.", user.first_name)
327 await update.message.reply_text(
328 text="Canceled.",
329 # "Bye! I hope we can talk again some day.",
330 reply_markup=MAIN_MENU
331 )
332 248
333 return ConversationHandler.END 249 return ConversationHandler.END
334 250
335 251
336class MsgDict(TypedDict): 252async def process_media_group(context: CallbackContext):
337 media_id: str
338 caption: str
339 status_id: int
340 content: str
341 chat_id: int
342
343
344async def media_group_sender(context: CallbackContext):
345 context.job.data = cast(List[MsgDict], context.job.data) 253 context.job.data = cast(List[MsgDict], context.job.data)
346 254
347 media_id = [] 255 media_id = []
348 chat_id = context.job.data[0].get("chat_id") 256 chat_id = context.job.data[0].get("chat_id")
349 for msg_dict in context.job.data: 257 for msg_dict in context.job.data:
350 if len(media_id) >= 4: 258 if len(media_id) >= 4:
351 print("Cannot attach more than 4 photos") 259 await context.bot.send_message(chat_id=chat_id, text=PROMPT_MAX_PHOTO_REACHED, reply_markup=MAIN_MENU)
352 break 260 return
261
353 file = await context.bot.get_file(msg_dict.get("media_id")) 262 file = await context.bot.get_file(msg_dict.get("media_id"))
354 img = io.BytesIO() 263 img = io.BytesIO()
355 await file.download_to_memory(img) 264 await file.download_to_memory(img)
@@ -364,20 +273,17 @@ async def media_group_sender(context: CallbackContext):
364 id=msg_dict.get("status_id"), 273 id=msg_dict.get("status_id"),
365 media_ids=media_id) 274 media_ids=media_id)
366 275
367 await context.bot.send_message(chat_id=chat_id, text="Done", 276 await context.bot.send_message(chat_id=chat_id, text=PROMPT_DONE, reply_markup=MAIN_MENU)
368 reply_markup=MAIN_MENU
369 )
370 277
371 278
372async def photo(update: Update, context: CallbackContext): 279async def callback_add_media(update: Update, context: CallbackContext):
373 """Stores the photo and asks for a location."""
374 await update.message.reply_chat_action(telegram.constants.ChatAction.TYPING) 280 await update.message.reply_chat_action(telegram.constants.ChatAction.TYPING)
375 281
376 try: 282 try:
377 await context.bot.delete_message(chat_id=update.message.chat_id, message_id=context.user_data["prompt_attach_photo_msg_id"]) 283 await context.bot.delete_message(chat_id=update.message.chat_id,
284 message_id=context.user_data[PROMPT_ADD_MEDIA])
378 except telegram.error.BadRequest as e: 285 except telegram.error.BadRequest as e:
379 if "not found" in str(e.message): 286 if "not found" in str(e.message):
380 print("prompt_attach_photo_msg already deleted")
381 pass 287 pass
382 288
383 status_id = context.user_data["status_id"] 289 status_id = context.user_data["status_id"]
@@ -398,8 +304,8 @@ async def photo(update: Update, context: CallbackContext):
398 if jobs: 304 if jobs:
399 jobs[0].data.append(msg_dict) 305 jobs[0].data.append(msg_dict)
400 else: 306 else:
401 context.job_queue.run_once(callback=media_group_sender, when=5, data=[msg_dict], 307 context.job_queue.run_once(callback=process_media_group, when=MEDIA_GROUP_TIMEOUT,
402 name=str(message.media_group_id)) 308 data=[msg_dict], name=str(message.media_group_id))
403 else: 309 else:
404 file = await update.message.effective_attachment[-1].get_file() 310 file = await update.message.effective_attachment[-1].get_file()
405 img = io.BytesIO() 311 img = io.BytesIO()
@@ -412,19 +318,16 @@ async def photo(update: Update, context: CallbackContext):
412 id=status_id, 318 id=status_id,
413 media_ids=media["id"]) 319 media_ids=media["id"])
414 320
415 await update.message.reply_text(text="Done", 321 await update.message.reply_text(text=PROMPT_DONE, reply_markup=MAIN_MENU)
416 reply_markup=MAIN_MENU
417 )
418 322
419 323
420async def skip_photo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 324async def callback_skip_media(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
421 query = update.callback_query 325 query = update.callback_query
422 await query.answer() 326 await query.answer()
423 327
424 await query.delete_message() 328 await query.delete_message()
425 await query.message.reply_text( 329 await query.message.reply_text(text=PROMPT_DONE, reply_markup=MAIN_MENU)
426 text="Done.", reply_markup=MAIN_MENU 330
427 )
428 return ConversationHandler.END 331 return ConversationHandler.END
429 332
430 333
@@ -434,35 +337,34 @@ def main() -> None:
434 checkin_handler = ConversationHandler( 337 checkin_handler = ConversationHandler(
435 entry_points=[ 338 entry_points=[
436 CommandHandler("start", start), 339 CommandHandler("start", start),
437 MessageHandler(filters.LOCATION, checkin), 340 MessageHandler(filters.LOCATION, callback_location_sharing),
438 ], 341 ],
439 states={ 342 states={
440 LOCATION: [ 343 WAIT_LOCATION: [
441 MessageHandler(filters.LOCATION, checkin), 344 MessageHandler(filters.LOCATION, callback_location_sharing),
442 ], 345 ],
443 LOCATION_SEARCH: [ 346 LOCATION_SEARCH_KEYWORD: [
444 MessageHandler(filters.TEXT, location_search_callback), 347 MessageHandler(filters.TEXT, callback_location_keyword_search),
445 CallbackQueryHandler(skip_location_search), 348 CallbackQueryHandler(callback_skip_location_keyword),
446 ], 349 ],
447 WAIT_LOC: [ 350 LOCATION_CONFIRMATION: [
448 CallbackQueryHandler(process_callback), 351 CallbackQueryHandler(callback_location_confirmation),
449 MessageHandler(filters.TEXT, manual_location_process_callback) 352 MessageHandler(filters.TEXT, callback_manual_location)
450 ], 353 ],
451 COMMENT: [ 354 ADD_COMMENT: [
452 MessageHandler(filters.TEXT, comment_callback), 355 MessageHandler(filters.TEXT, callback_add_comment),
453 CallbackQueryHandler(skip_comment_callback), 356 CallbackQueryHandler(callback_skip_comment),
454 ], 357 ],
455 PHOTO: [MessageHandler(filters.PHOTO, photo), 358 ADD_MEDIA: [MessageHandler(filters.PHOTO, callback_add_media),
456 CallbackQueryHandler(skip_photo)], 359 CallbackQueryHandler(callback_skip_media)],
457 }, 360 },
458 fallbacks=[CommandHandler("cancel", cancel)], 361 fallbacks=[CommandHandler("cancel", cancel)],
459 per_message=False, 362 per_message=False,
460 allow_reentry=True, 363 allow_reentry=True,
461 ) 364 )
462 365
463 application.add_handler(checkin_handler, 1) 366 application.add_handler(CommandHandler("help", help_command))
464 367 application.add_handler(checkin_handler)
465 # Run the bot until the user presses Ctrl-C
466 application.run_polling() 368 application.run_polling()
467 369
468 370
diff --git a/config.py b/config.py
index 2469d0f..3356d11 100644
--- a/config.py
+++ b/config.py
@@ -12,3 +12,5 @@ TOOT_API_BASE_URL = config["TOOT"]["API_BASE_URL"]
12TOOT_CLIENT_ID = config["TOOT"]["CLIENT_ID"] 12TOOT_CLIENT_ID = config["TOOT"]["CLIENT_ID"]
13TOOT_CLIENT_SECRET = config["TOOT"]["CLIENT_SECRET"] 13TOOT_CLIENT_SECRET = config["TOOT"]["CLIENT_SECRET"]
14TOOT_ACCESS_TOKEN = config["TOOT"]["ACCESS_TOKEN"] 14TOOT_ACCESS_TOKEN = config["TOOT"]["ACCESS_TOKEN"]
15
16MEDIA_GROUP_TIMEOUT = 3
diff --git a/prompt/string.py b/prompt/string.py
new file mode 100644
index 0000000..af3363a
--- /dev/null
+++ b/prompt/string.py
@@ -0,0 +1,12 @@
1PROMPT_CHOOSE_ACTION = "Use bot keyboard to choose an action"
2PROMPT_ADD_COMMENT = "You can continue adding comments, or press skip"
3PROMPT_ADD_MEDIA = "You can continue adding photos, or press skip"
4PROMPT_LOCATION_KEYWORD = "You can input location search keywords or press skip"
5PROMPT_NO_NEARBY_POI = "No nearby places found. You can input location name manually"
6PROMPT_CHOOSE_POI_FROM_LIST = "Where are you?"
7PROMPT_HELP = "Use /start to test this bot."
8PROMPT_CANCELED = "Canceled"
9PROMPT_MAX_PHOTO_REACHED = "Cannot attach more than 4 medias, only first 4 will be posted"
10PROMPT_DONE = "Done"
11
12CALLBACK_SKIP = "Skip"
Powered by cgit v1.2.3 (git 2.41.0)