def isQueryValid(queryTime): timeNow = Time.getDateTimeObject(Time.getDateTime()) try: delta = timeNow - queryTime if delta.total_seconds() / 60 < 1: return True else: return False except: print(TAG, FAILED, "isQueryValid()") return False
def webhook(request): print(TAG, "Request received!") bot = telegram.Bot(token=BOT_TOKEN) if request.method == "POST": update = telegram.Update.de_json(request.get_json(force=True), bot) if update == None: print(TAG, FAILED, "Update == NONE") return callbackQuery = update.callback_query if callbackQuery != None: query = callbackQuery.data chatID = callbackQuery.message.chat_id print(TAG, UPDATE_1, chatID, callbackQuery.message.from_user.first_name, query) if query == "PIN": bot.sendMessage(chat_id=chatID, text="Please enter your 4-digit PIN", disable_notification=True) query_ref = db.collection("querying").document("replies") query_ref.set({ str(chatID): "setpin " + Time.getDateTime() }, merge=True) print(TAG, UPDATE_1, query, SUCCESSFUL) elif query == "URL": bot.sendMessage(chat_id=chatID, text="Please enter your URL\n\nE.g: https://temptaking.ado.sg/group/uniqueCode", disable_notification=True) query_ref = db.collection("querying").document("replies") query_ref.set({ str(chatID): "seturl " + Time.getDateTime() }, merge=True) print(TAG, UPDATE_1, query, SUCCESSFUL) elif query == "SENDER": bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = db.collection("chatrooms").document(str(chatID)).get().to_dict() doesURLexist = "sendurl" in cr_details_dict if doesURLexist: try: reply_markup = getMemberNamesKeyboardMarkup(cr_details_dict["sendurl"]) except: print("Connection to server failed") bot.sendMessage(chat_id=chatID, text="⚠ Temptaking.ado.sg server seems to be down. Please try again later!", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) return query_ref = db.collection("querying").document("replies") query_ref.set({ str(chatID): "setsender " + Time.getDateTime() }, merge=True) bot.sendMessage(chat_id=chatID, text="👾 Please select your name below", reply_markup=reply_markup, disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="⚠ URL required to set sender!\n\n/url to set url", disable_notification=True) print(TAG, UPDATE_1, query, SUCCESSFUL) elif query == "TRACKURL": bot.sendMessage(chat_id=chatID, text="Please enter the tracking URL\n\nE.g: https://temptaking.ado.sg/overview/uniqueCode", disable_notification=True) query_ref = db.collection("querying").document("replies") query_ref.set({ str(chatID): "settrackurl " + Time.getDateTime() }, merge=True) print(TAG, UPDATE_1, query, SUCCESSFUL) return if update.message == None or update.message.text == None: print(TAG, FAILED, "Message == None") return message = update.message.text chatID = update.message.chat_id print(TAG, UPDATE_2, str(chatID), update.message.from_user.first_name, message) if message.startswith("/"): cr_ref = db.collection("chatrooms").document(str(chatID)) cr_details = cr_ref.get() if not cr_details.exists: cr_ref.set({ "groupType": update.message.chat.type, "groupTitle": update.message.chat.title, "first_name": update.message.chat.first_name, }) if message.startswith("/start"): try: bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) welcomeMessage = "🌟 Welcome to TempAdoBot\! 🌟\n\n" + \ "__With me, you can__\n" + \ "🏹 get daily reminders for temperature submissions\n" + \ "🏹 send temperatures directly\n" + \ "🏹 check your temperature records for the day\n" + \ "🏹 check who have not send their temperatures\n\n" + \ "/setup to start sending temperatures\n" + \ "/help for all available commands" bot.sendMessage(chat_id=chatID, text=welcomeMessage, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) except: print("Error occured when broadcasting to", chatID, "Did he block me?") elif message.startswith("/help"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) header = "✋ *TempAdoBot Help Page* ✋\n\n" commands = "/help \- help page for this bot\n" + \ "/status \- check if temptaking\.ado services are available\n\n" + \ "📣 If you are new:\n" + \ "/setup \- a one\-time setup to upload temperatures\n\n" + \ "📣 Uploading of temperature records:\n" + \ "/pin \- change your pin\n" + \ "/url \- change your url\n" + \ "/sender \- change who you are \n" + \ "/history \- view temperature submissions for today\n" + \ "/sendtemp \- send your temperature\n\n" + \ "📣 Tracking of everyone\'s temperature records \(For commanders\?\):\n" + \ "/track \- see who have yet to upload their temperatures\n\n" + \ "💡 Subscribing to reminders:\n" + \ "/subscribe \- get daily reminders at 1100 and 1530\n" + \ "/unsubscribe \- unsubscribe to daily reminders" text = header + commands bot.sendMessage(chat_id=chatID, text=text, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) elif message.startswith("/setup"): try: bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) messageText = "__Getting started__\n\n" + \ "1️⃣ Setup your PIN\n" + \ "2️⃣ Setup you URL\n" + \ "3️⃣ Setup your identity\n" + \ "4️⃣ Start sending your temperatures\!" button_list = [ [telegram.InlineKeyboardButton("🔑 Set PIN", callback_data="PIN"), telegram.InlineKeyboardButton("🌐 Set URL", callback_data="URL")], [telegram.InlineKeyboardButton("🙆♂️ Set sender", callback_data="SENDER")] ] reply_markup = telegram.InlineKeyboardMarkup(button_list) bot.sendMessage(chat_id=chatID, text=messageText, reply_markup=reply_markup, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) except: print("Error occured when broadcasting to", chatID, "Did he block me?") elif message.startswith("/pin"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = cr_details.to_dict() print(cr_details_dict, str(update.message.from_user.id), ("sendpin " + str(update.message.from_user.id)) in cr_details_dict) doesPINexist = ("sendpin " + str(update.message.from_user.id)) in cr_details_dict pin = None inlineButtonText = "🔑 Set PIN" messageText = "🔒 You have not setup your PIN!" if doesPINexist: pin = cr_details_dict["sendpin " + str(update.message.from_user.id)] inlineButtonText = "🔑 Change PIN" messageText = "🔓 Your PIN is: " + pin button_list = [ telegram.InlineKeyboardButton(inlineButtonText, callback_data="PIN") ] reply_markup = telegram.InlineKeyboardMarkup([button_list]) bot.sendMessage(chat_id=chatID, text=messageText, reply_markup=reply_markup, disable_notification=True) elif message.startswith("/url"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = cr_details.to_dict() doesURLexist = "sendurl" in cr_details_dict url = None inlineButtonText = "🌐 Set URL" messageText = "⚠ You have not setup your URL!" if doesURLexist: url = cr_details_dict["sendurl"] inlineButtonText = "🌐 Change URL" messageText = "🌏 URL to send temperature records:\n\n" + url button_list = [ telegram.InlineKeyboardButton(inlineButtonText, callback_data="URL") ] reply_markup = telegram.InlineKeyboardMarkup([button_list]) bot.sendMessage(chat_id=chatID, text=messageText, reply_markup=reply_markup, disable_notification=True) elif message.startswith("/sender"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = cr_details.to_dict() print(cr_details_dict, str(update.message.from_user.id), str(update.message.from_user.id) in cr_details_dict) doesSenderExist = str(update.message.from_user.id) in cr_details_dict sender = None inlineButtonText = "🙆♂️ Set sender" messageText = "👻 You have not identified yourself!" if doesSenderExist: sender = cr_details_dict[str(update.message.from_user.id)] inlineButtonText = "💁♂️ Change sender" messageText = "🧔 " + update.message.from_user.first_name + " is currently bound to " + sender button_list = [ telegram.InlineKeyboardButton(inlineButtonText, callback_data="SENDER") ] reply_markup = telegram.InlineKeyboardMarkup([button_list]) bot.sendMessage(chat_id=chatID, text=messageText, reply_markup=reply_markup, disable_notification=True) elif message.startswith("/history"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = cr_details.to_dict() doesURLexist = "sendurl" in cr_details_dict doesPINexist = "sendpin " + str(update.message.from_user.id) in cr_details_dict doesSenderExist = str(update.message.from_user.id) in cr_details_dict if doesURLexist and doesPINexist and doesSenderExist: URL = cr_details_dict["sendurl"] GROUPCODE = None #temp code to cache groupcodes try: GROUPCODE = cr_details_dict["groupCode"] except: GROUPCODE = URL[URL.rindex("/") + 1:] cr_ref.set({ "groupCode": GROUPCODE }, merge=True) MEMBERNAME = cr_details_dict[str(update.message.from_user.id)] MEMBERID = None try: MEMBERID = getMemberIdFromName(URL, MEMBERNAME) except: bot.sendMessage(chat_id=chatID, text="⚠ Your name can't be found in the list.\n\nTemptaking.ado.sg may be down or your URL and sender name are incorrect", disable_notification=True) return PIN = cr_details_dict["sendpin " + str(update.message.from_user.id)] data = { "groupCode": GROUPCODE, "memberId": MEMBERID, "pin": PIN, "startDate": Time.getDate(), "endDate": Time.getDate(), "timezone": Time.TIME_ZONE } try: response = requests.post(url=HISTORY_URL, data=data, timeout=10).text responseDict = json.loads(response)[0] latestAM = responseDict["latestAM"] latestPM = responseDict["latestPM"] if latestAM == "": latestAM = "NO DATA" if latestPM == "": latestPM = "NO DATA" messageText = "☀ AM temperature: " + latestAM + "\n" + \ "🌙 PM temperature: " + latestPM except: messageText = "😢 Looks like temptaking.ado.sg is down. Please try again later!" bot.sendMessage(chat_id=chatID, text=messageText, disable_notification=True) else: criteria = getSendTempCriteria(doesURLexist, doesPINexist, doesSenderExist) button_list = getCriteriaFailedInline(doesURLexist, doesPINexist, doesSenderExist) reply_markup = telegram.InlineKeyboardMarkup([button_list]) bot.sendMessage(chat_id=chatID, text=criteria, reply_markup=reply_markup, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) elif message.startswith("/sendtemp"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = cr_details.to_dict() doesURLexist = "sendurl" in cr_details_dict doesPINexist = "sendpin " + str(update.message.from_user.id) in cr_details_dict doesSenderExist = str(update.message.from_user.id) in cr_details_dict if doesURLexist and doesPINexist and doesSenderExist: reply_markup = getTemperatureKeyboardMarkup() query_ref = db.collection("querying").document("replies") query_ref.set({ str(chatID): "sendtemp " + Time.getDateTime() }, merge=True) bot.sendMessage(chat_id=chatID, text="📤 Please select your temperature below 📤\n\n__You are reminded to take your temperature first\!__", reply_markup=reply_markup, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) else: criteria = getSendTempCriteria(doesURLexist, doesPINexist, doesSenderExist) button_list = getCriteriaFailedInline(doesURLexist, doesPINexist, doesSenderExist) reply_markup = telegram.InlineKeyboardMarkup([button_list]) bot.sendMessage(chat_id=chatID, text=criteria, reply_markup=reply_markup, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) elif message.startswith("/track"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) cr_details_dict = cr_details.to_dict() doesURLexist = "checkurl" in cr_details_dict inlineButtonText = "🌐 Set tracking URL" messageText = "⚠ You have not setup your URL!\n\n" + \ "A tracking URL is required, which is different from the one used to send temperatures\n\n" + \ "Use /history instead to view your temperature history" if doesURLexist: inlineButtonText = "🌐 Change tracking URL" try: data = track.getGroupData(cr_details_dict["checkurl"]) messageText = track.formatReminder(data) except: messageText = "temptaking.ado.sg seems to be down. Please try again later." button_list = [ telegram.InlineKeyboardButton(inlineButtonText, callback_data="TRACKURL") ] reply_markup = telegram.InlineKeyboardMarkup([button_list]) bot.sendMessage(chat_id=chatID, text=escape_markdown(messageText, version=2), parse_mode=telegram.ParseMode.MARKDOWN_V2, reply_markup=reply_markup, disable_notification=True) elif message.startswith("/subscribe") or message.startswith("/unsubscribe"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) sub_ref = db.collection("subscribers").document("reminderSubscribers") sub_details_dict = sub_ref.get().to_dict() if message.startswith("/subscribe"): if str(chatID) not in sub_details_dict or not sub_details_dict[str(chatID)]: sub_ref.set({ str(chatID): True }, merge=True) bot.sendMessage(chat_id=chatID, text="💡 Subscribed!\n\n" + \ "You will now receive reminders for AM and PM temperatures", disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="💡 You have already subscribed!", disable_notification=True) else: if str(chatID) in sub_details_dict and sub_details_dict[str(chatID)]: sub_ref.set({ str(chatID): False }, merge=True) bot.sendMessage(chat_id=chatID, text="🍼 Unsubscribed!\n\n" + \ "You will not receive reminders for AM and PM temperatures", disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="🍼 You have not subscribed!", disable_notification=True) elif message.startswith("/broadcast " + ADMIN_TOKEN): if len(message.split(" ")) < 3: bot.sendMessage(chat_id=chatID, text="⚠ Invalid Syntax: /broadcast <TOKEN> <MESSAGE>", disable_notification=True) return header = "Message from TempAdoBot:" bodyList = message.split(" ")[2:] body = " ".join(bodyList) text = header + "\n\n" + body chats = getAllChats() for chatID in chats: try: bot.sendMessage(chat_id=chatID, text=text) except: print("Error occured when broadcasting to", chatID, "Did he block me?") elif message.startswith("/status"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) send_details_dict = db.collection("status").document("send").get().to_dict() track_details_dict = db.collection("status").document("track").get().to_dict() send_details_list = list(send_details_dict) track_details_list = list(track_details_dict) send_details_list.sort() send_details_list.sort(key=lambda x: x.split(" ")[0].split("/")[1]) track_details_list.sort() track_details_list.sort(key=lambda x: x.split(" ")[0].split("/")[1]) latestSendCheckTiming = send_details_list[-1] latestTrackCheckTiming = track_details_list[-1] text = "Send Service Status:\n\n" + \ "Service Online: " + str(send_details_dict[latestSendCheckTiming]) + "\n" + \ "Last checked: " + latestSendCheckTiming + "\n\n" + \ "Track Service Status:\n\n" + \ "Service Online: " + str(track_details_dict[latestTrackCheckTiming]) + "\n" + \ "Last checked: " + latestTrackCheckTiming bot.sendMessage(chat_id=chatID, text=text, disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="⚠ Invalid command!\n\n/help for a list of available commands", disable_notification=True) else: query_ref = db.collection("querying").document("replies") query_details = query_ref.get() if not query_details.exists: return query_details_dict = query_details.to_dict() print(query_details_dict, str(chatID),str(chatID) in query_details_dict) isBotQuerying = str(chatID) in query_details_dict if isBotQuerying: cr_ref = db.collection("chatrooms").document(str(chatID)) queryType = query_details_dict[str(chatID)] if queryType.startswith("setsender"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.TYPING) query_ref.update({ str(chatID): firestore.DELETE_FIELD }) #ensure query time is not too long ago (1 min) if not isQueryValid(Time.getDateTimeObject(queryType[10:])): bot.sendMessage(chat_id=chatID, text="⌛ Command /setsender timeout. Please try again", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) return #ensure member is valid cr_details = cr_ref.get() cr_details_dict = cr_details.to_dict() doesURLexist = "sendurl" in cr_details_dict doesPINexist = "sendpin " + str(update.message.from_user.id) in cr_details_dict if doesURLexist: URL = cr_details_dict["sendurl"] try: members = list(map(lambda x: x["identifier"], getMemberCodeData(URL))) except: bot.sendMessage(chat_id=chatID, text="⚠ Temptaking.ado.sg server seems to be down. Please try again later!", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) return if message not in members: bot.sendMessage(chat_id=chatID, text="⚠ " + message + " not a valid member! /sender to try again", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) return cr_ref.set({ str(update.message.from_user.id): message }, merge=True) bot.sendMessage(chat_id=chatID, text="🧔 Sender set!\n\n" + update.message.from_user.first_name + " is now bound to " + message, reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) elif queryType.startswith("sendtemp"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.UPLOAD_DOCUMENT) query_ref.update({ str(chatID): firestore.DELETE_FIELD }) #ensure query time is not too long ago (1 min) if not isQueryValid(Time.getDateTimeObject(queryType[9:])): bot.sendMessage(chat_id=chatID, text="⌛ Command timeout. Please try again", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) return cr_details = cr_ref.get() cr_details_dict = cr_details.to_dict() doesURLexist = "sendurl" in cr_details_dict doesPINexist = "sendpin " + str(update.message.from_user.id) in cr_details_dict doesMemberexist = str(update.message.from_user.id) in cr_details_dict if doesURLexist and doesPINexist and doesMemberexist: URL = cr_details_dict["sendurl"] MEMBERNAME = cr_details_dict[str(update.message.from_user.id)] MEMBERID = None try: MEMBERID = getMemberIdFromName(URL, MEMBERNAME) except: bot.sendMessage(chat_id=chatID, text="⚠ Your name can't be found in the list.\n\nTemptaking.ado.sg may be down or your URL and sender name are incorrect", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) return TEMPERATURE = message PIN = cr_details_dict["sendpin " + str(update.message.from_user.id)] try: reply = sendTemperature(URL, MEMBERID, TEMPERATURE, PIN) if reply == "OK": bot.sendMessage(chat_id=chatID, text="🌡 Temperature sent!\n\n", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) elif "Wrong pin" in reply: bot.sendMessage(chat_id=chatID, text="⚠ PIN inputted was wrong!\n\n/pin to reset pin!", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) except : bot.sendMessage(chat_id=chatID, text="⚠ Temperature failed to send!\n\ntemptaking.ado.sg seems to be down. Please try again later!", reply_markup=telegram.ReplyKeyboardRemove(), disable_notification=True) print(TAG, FAILED, "sendtemp") else: criteria = getSendTempCriteria(doesURLexist, doesPINexist, doesMemberexist) bot.sendMessage(chat_id=chatID, text=criteria, parse_mode=telegram.ParseMode.MARKDOWN_V2, disable_notification=True) elif queryType.startswith("setpin"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.UPLOAD_DOCUMENT) query_ref.update({ str(chatID): firestore.DELETE_FIELD }) #ensure query time is not too long ago (1 min) if not isQueryValid(Time.getDateTimeObject(queryType[7:])): bot.sendMessage(chat_id=chatID, text="⌛ Command timeout. Please try again", disable_notification=True) return pin = message try: if isSendPINValid(pin): cr_ref.set({ "sendpin " + str(update.message.from_user.id): pin }, merge=True) bot.sendMessage(chat_id=chatID, text="✅ " + update.message.from_user.first_name + "'s PIN set as: " + pin + "\n\n/pin to retrieve PIN", disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="⚠ Invalid PIN!\n\nPINs are 4-digit numbers! Eg: 0000", disable_notification=True) except (PINLengthError, ValueError) as e: print("[main.py] webhook: /pin -- " + str(e)) bot.sendMessage(chat_id=chatID, text="⚠ Invalid PIN!\n\nPINs are 4-digit numbers! Eg: 0000", disable_notification=True) elif queryType.startswith("seturl"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.UPLOAD_DOCUMENT) query_ref.update({ str(chatID): firestore.DELETE_FIELD }) #ensure query time is not too long ago (1 min) if not isQueryValid(Time.getDateTimeObject(queryType[7:])): bot.sendMessage(chat_id=chatID, text="⌛ Command timeout. Please try again", disable_notification=True) return url = message try: groupCode = url[url.rindex("/") + 1:] if isSendURLValid(url): cr_ref.set({ "sendurl": url, "groupCode": groupCode }, merge=True) bot.sendMessage(chat_id=chatID, text="✅ URL set as:\n\n" + url, disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="⚠ Invalid URL!\n\nURL Example: https://temptaking.ado.sg/group/uniqueCode", disable_notification=True) except (MissingPrefixError, InvalidURLError, InvalidCodeError) as e: print("[main.py] webhook: /setcheckurl -- " + str(e)) bot.sendMessage(chat_id=chatID, text="⚠ " + str(e), disable_notification=True) except: print("[main.py] webhook: /setcheckurl -- Unknown Error occurred") bot.sendMessage(chat_id=chatID, text="⚠ Invalid URL!\n\nURL Example: https://temptaking.ado.sg/group/uniqueCode", disable_notification=True) elif queryType.startswith("settrackurl"): bot.sendChatAction(chat_id=chatID, action=telegram.ChatAction.UPLOAD_DOCUMENT) query_ref.update({ str(chatID): firestore.DELETE_FIELD }) #ensure query time is not too long ago (1 min) if not isQueryValid(Time.getDateTimeObject(queryType[12:])): bot.sendMessage(chat_id=chatID, text="⌛ Command timeout. Please try again", disable_notification=True) return url = message try: if isCheckURLValid(url): cr_ref.set({ "checkurl": url }, merge=True) bot.sendMessage(chat_id=chatID, text="✅ Tracking URL set as:\n\n" + url, disable_notification=True) else: bot.sendMessage(chat_id=chatID, text="⚠ Invalid URL!\n\nURL Example: https://temptaking.ado.sg/overview/uniqueCode", disable_notification=True) except (MissingPrefixError, InvalidURLError) as e: print("[main.py] webhook: /setcheckurl -- " + str(e)) bot.sendMessage(chat_id=chatID, text="⚠ " + str(e), disable_notification=True) except: print("[main.py] webhook: /setcheckurl -- Unknown Error occurred") bot.sendMessage(chat_id=chatID, text="⚠ Invalid URL!\n\nURL Example: https://temptaking.ado.sg/group/uniqueCode", disable_notification=True) return "ok"