def add_edit_nick(update: Update, context: CallbackContext) -> int: # SET_NICK """Adds or updates your nickname. Then goes back to main menu.""" chat_id = update.effective_chat.id msg_id = update.message.message_id if 'nickname' not in context.user_data: context.user_data['nickname'] = [] if any(bad_word in update.message.text.lower().split() for bad_word in prohibited): context.bot.send_message( chat_id=chat_id, reply_markup=ForceReply(selective=True), reply_to_message_id=msg_id, text= "See this language is embarrassing to me ok. I'm giving you one more chance " "that's it.") return SET_NICK else: context.user_data['nickname'].append(update.message.text) nicky = context.user_data['nickname'][-1] context.bot.send_message(chat_id=chat_id, text=f"Hi {nicky} what you're doing like", reply_to_message_id=msg_id, reply_markup=markup) logger( message= f"{update.effective_user.first_name} just changed their nickname to {nicky}." ) return CHOICE
def reply(update: Update, context: CallbackContext) -> None: """ This function checks if the user is replying to a message of this bot in a group, if it is, it sends a reply to that person. Same behaviour applies for this bot mentions in replies (reply to anyone, not just this bot). """ text = update.message.text if update.message.reply_to_message.from_user.username == context.bot.username: # If the reply is to this bot: if not (text.startswith('!r') or text.endswith('!r') ): # Don't reply if this is prepended or appended. logger( message= f"Bot received a reply from {update.effective_user.first_name} in " f"{update.effective_chat.title}.") shanifier(update, context, is_group=True, the_id=update.message.message_id) elif context.bot.name in text: shanifier(update, context, is_group=True, the_id=update.message.message_id) del text
def facts(update: Update, context: CallbackContext) -> None: """Sends one random fact to the user.""" del_command(update) context.bot.send_message(chat_id=update.effective_chat.id, text=r.choice(util.facts())) logger(update=update, message=f"/facts", command=True)
def magic8ball(update: Update, context: CallbackContext) -> int: """Asks the user for the question.""" chat_id = update.effective_chat.id name = get_nick(update, context) initiate = ( "If you have a doubt, just type it here", f"{name}, are you confused? Ask me and I'll search for some sow...so..solutions" " okay?", "I can predict the future like you say . Just ask me. I'm just trying to find you option", "Fast fast no time ask me!", "See tell me what's the confusion", f"Yes {name}?") context.bot.send_chat_action(chat_id=chat_id, action='typing') sleep(1) # Sends message with a force reply context.bot.send_message( chat_id=chat_id, text=f"{r.choice(initiate)}🔮\nOr, type /cancel so I won't mind that\n" f"(Reply to this message for this to work!)", reply_markup=ForceReply(force_reply=True, selective=True), reply_to_message_id=update.message.message_id) logger(message=f"/8ball", command=True, update=update) del chat_id, name return PROCESSING # Will go into first (and only) state in convo handler in main.py
def update_event(self, new_date: datetime.datetime): """ Updates the event in Google Calendar. Parameter 'new_date' must be specified, 'date' need not be specified in class instance. """ # Get event id of the event to be modified events = service.events().list(calendarId='primary').execute() for event in events['items']: if self.name in event['summary']: print(f"Match: {event['summary']}") self.event['start']['date'] = f"{formatter(new_date)}" self.event['end'][ 'date'] = f"{formatter(new_date + timedelta(days=1))}" updated_event = service.events().update( calendarId='primary', eventId=event['id'], body=self.event).execute() logger( f"Successfully updated {self.name}'s birthday: {updated_event['start']['date']}." ) break else: raise ValueError("Event not found")
def de_pin(update: Update, context: CallbackContext) -> None: """Deletes pinned message service status from the bot.""" context.bot.delete_message(chat_id=update.effective_chat.id, message_id=update.message.message_id) logger( message= f"Bot deleted a pinned service message from {update.effective_chat.title}." )
def unknown(update: Update, context: CallbackContext) -> None: """When user uses an invalid command.""" context.bot.send_message(chat_id=update.effective_chat.id, text="I didn't say wrong I don't know.") logger( message= f"{update.effective_user.first_name} just used something weird in {get_chat_name(update)}." )
def add_event(self) -> None: """ Adds event to Google Calendar. Name and date must be specified in the class instance. """ if self.date is None: raise ValueError("Date must be specified!") service.events().insert(calendarId='primary', body=self.event).execute() logger(message=f"{self.event['summary']} was added.")
def snake(update: Update, context: CallbackContext) -> None: """Sends a roast to the user.""" del_command(update) with open(r"files/snake.txt", "r") as f1: context.bot.send_message(chat_id=update.effective_chat.id, text=f1.read()) logger(update=update, message=f"/snake", command=True)
def del_command(update: Update) -> None: """Deletes the command message sent by the user.""" try: update.message.delete() except error.BadRequest as e: logger( message= f"The command {update.message.text} could not be deleted due to {e}." )
def timedout(update: Update, context: CallbackContext) -> None: """This is called when a user has timed out while using /tell (after 35 seconds).""" context.bot.send_message(chat_id=update.effective_chat.id, text="Ok I am fine being seenzoned", reply_to_message_id=update.message.message_id, reply_markup=ReplyKeyboardRemove(selective=True)) logger( message= f"{update.effective_user.first_name} just timed out while using /tell." )
def bday_del(update: Update, context: CallbackContext) -> int: # MODIFY """Deletes birthday from our records. Then goes back to main menu.""" name = get_nick(update, context) context.bot.send_message(chat_id=update.effective_chat.id, text=f"Ok {name}, I forgot your birthday", reply_to_message_id=update.message.message_id, reply_markup=markup) logger(message=f"{update.effective_user.first_name} just deleted their birthday.") del context.user_data['birthday'] return CHOICE
def wish(context: CallbackContext) -> None: """Gets the next birthday from Google Calendar and wishes you if today is your birthday.""" gcalendar.main() days_remaining, name = gcalendar.get_next_bday() bday_msgs = ( f"Happy birthday {name}! !🎉 I don't know why like, but I know you despise me with the burning " f"passion of a thousand suns. I don't give a flux, like you say. I implore you to let go of " f"hate and embrace love. Spend the rest of your days with love in your heart and faith in your " f"soul. Life's cyclotron may sometimes send you tumbling around, but remember that it is " f"necessary to do so in order to hit the targit. Negative emotions act as charge for the " f"velocity selector of life. Remove them from your being and you shall not stray from the " f"straight path. I wish you the best. May your jockeys be unpressed and your apertures small. " f"Enjoy your 18th. Forget about coronabitch. Godspeed.", f"Happy birthday {name}! I wish you the best of luck for life. Remember: You matter. Until you " f"multiply yourself times the speed of light squared. Then you energy, like you say!🎉 What " f"your going to do today like?", f"Happy birthday {name}! !🎉 What your going to do today like?") # Wishes from Google Calendar- if days_remaining == 0: _12B = group_ids['12b'] msg = context.bot.send_message(chat_id=_12B, text=bday_msgs[2]) context.bot.pin_chat_message(chat_id=_12B, message_id=msg.message_id, disable_notification=True) logger( message= f"Happy birthday message for {name} was just sent to the 12B group." ) now = str(date.today()) today = datetime.strptime( now, "%Y-%m-%d" ) # Parses today's date (time object) into datetime object new_date = today.replace(year=today.year + 1) gcalendar.CalendarEventManager(name=name).update_event( new_date) # Updates bday to next year del _12B, msg, now, today, new_date elif days_remaining in (21, 69): context.bot.send_message( chat_id=group_ids['12b'], text=f"{name}'s birthday is in {days_remaining} days!!") logger( message= f"Happy birthday reminder for {name}({days_remaining} days) was just sent to the 12B group." ) del days_remaining, name
def timedout(update: Update, context: CallbackContext) -> None: """Called when the user does not respond to /8ball after 35 seconds.""" context.bot.send_message( chat_id=update.effective_chat.id, text= f"Ok, {get_nick(update, context)} don't tell me your problem. I have other things " f"to do like", reply_to_message_id=update.message.message_id, reply_markup=ReplyKeyboardRemove(selective=True)) logger(message= f"{update.effective_user.first_name} just timed out using /8ball.")
def cancel(update: Update, context: CallbackContext) -> int: """Called when user presses /cancel""" context.bot.send_message( chat_id=update.effective_chat.id, text= "I just wanted to be in the right direction nothing else I mean okay?", reply_to_message_id=update.message.message_id, reply_markup=ReplyKeyboardRemove(selective=True)) logger( message=f"{update.effective_user.first_name} just cancelled /8ball.") return -1
def del_nick(update: Update, context: CallbackContext) -> int: # MODIFY_NICK """Deletes nickname (i.e.) sets it to your first name.""" name = update.message.from_user.first_name context.user_data['nickname'].append(name) context.bot.send_message(chat_id=update.effective_chat.id, text=f"I'm forgetting your nic.. {name}", reply_to_message_id=update.message.message_id, reply_markup=markup) logger(message=f"{name} just deleted their nickname.") return CHOICE
def save(update: Update, _: CallbackContext) -> int: # UPDATED """Called when user clicks save. Saves all applied settings into database.""" global morn_setting chat_id = update.effective_chat.id responses = ("I updated my behaviour", "See I got the clarity now", r"I will now like you do fo\.\.follow this", "Ok I will do this now it's not that hard", "I am now in the right direction") confirmations = ("Now I'm like this:", "This is okay with me now like:", "Okay fine I'm okay with this:", "I have like you say changed now:", "My new behaviour is:") # Show settings have been updated- update.callback_query.edit_message_text( text=r.choice(responses) + f"\n\n{r.choice(confirmations)}\n" + msg[36:], parse_mode="MarkdownV2") logger( message= f"{update.effective_user.first_name} just updated {get_chat_name(update)}'s settings to:\n" f"Media={media_prob}, Profanity={profane_prob}, Morning quotes={morn_setting}." ) c.execute( f"UPDATE CHAT_SETTINGS SET MORNING_MSGS='{morn_setting}' WHERE CHAT_ID={chat_id};" ) conn.commit() # Checks if group name has changed, if it did, updates in db- c.execute(f"SELECT CHAT_NAME FROM CHAT_SETTINGS WHERE CHAT_ID={chat_id};" ) # Gets name from db result = c.fetchone() name = get_chat_name(update) # Gets name of chat if name != result[0]: # If the name is not the same, update it in db c.execute( f"UPDATE CHAT_SETTINGS SET CHAT_NAME='{name}' WHERE CHAT_ID={chat_id};" ) conn.commit() conn.close() # Close connection, we don't want mem leaks del name, chat_id, responses, confirmations, result return -1
def send_quiz(context: CallbackContext) -> None: """ Sends 5 quizzes to target chat (tms group for now). Also sets a timer for 24 hours for quiz expiry (using jobs). """ right_now = datetime.now() # returns: Datetime obj if 'last_quiz' not in context.bot_data: context.bot_data['last_quiz'] = right_now diff = right_now - context.bot_data['last_quiz'] logger(message=f"Last quiz was sent {diff.days} days ago.") if diff.days < 7: print("Not enough days for next quiz!") return context.bot_data['sent_quizzes'] = [] starts = ("See I'm keeping one quizizz now okay. You have one day to finish. For boards ok. I want everyone to do " "it that's it.", "I have kept one quizizz now. I expect something okay.", "Because of the bad like you say situation I have kept this online quizizz now. Do fast okay.", "I'm sending these 5 questions now like. I want it to be done by tomorrow okay? Fast fast") context.bot.send_message(chat_id=group_ids['grade12'], text=r.choice(starts)) context.bot.send_chat_action(chat_id=group_ids['grade12'], action='typing') # Get our questions, choices and answers from the web- questions, choices, answers = quiz_scraper.quiz_maker_v2(number=5) # Support sending quiz to tms group only for now- for question, choice, answer in zip(questions, choices, answers): quiz = context.bot.send_poll(chat_id=group_ids['grade12'], question=question, options=choice, is_anonymous=False, type=Poll.QUIZ, correct_option_id=answer, is_closed=False) context.bot_data['sent_quizzes'].append(quiz) logger(message=f"The 5 quizzes were just sent to tms group successfully.") if right_now.day not in (29, 30, 31): # If not in final days of a month, set date 2 days after context.bot_data['stop_quiz_date'] = datetime(right_now.year, right_now.month, right_now.day + 2) else: # TODO: Contingency for new year context.bot_data['stop_quiz_date'] = datetime(right_now.year, right_now.month + 1, 1) context.bot_data['last_quiz'] = right_now # Save new time for last quiz context.dispatcher.persistence.flush()
def swear(update: Update, context: CallbackContext) -> None: """Sends 4 swear words to the user along with a message saying not to use them.""" del_command(update) while True: swears = r.choices(tuple(prohibited), k=4) # Returns a list of 4 elements if len(set(swears)) == len( swears): # i.e. if there is a duplicate element break context.bot.send_message( chat_id=update.effective_chat.id, text=ladcased( f"'{swears[0]}',\n'{swears[1]}',\n'{swears[2]}',\n'{swears[3]}'\n\n" f"{next(swear_advice)}")) logger(update=update, message=f"/swear", command=True)
def before_all(context): context.log = logger() context.timeshift = TimeshiftHelper(context) context.unit = UnitHelper(context) context.cnb = CNBMock(context) context.cnb.start() context.unit.configure() context.unit.download() context.timeshift.bootstrap()
def welcome(update: Update, context: CallbackContext) -> None: """ Greets new users in the TMS group and also sends a link to the Introducing Telegram channel where they can learn more about Telegram. """ user = update.message.new_chat_members[0] if user.is_bot: return logger(message=f"{user.full_name} just joined the TMS group!") context.bot.send_message( chat_id=update.effective_chat.id, text=f'Welcome to the TMS group ' f'{user.mention_html()}! I want you to know all Telegram like you say features okay? ' f'Check out this ' f'<a href="https://t.me/IntroducingTelegram">channel</a> to know everything!', parse_mode="HTML")
def start(update: Update, context: CallbackContext) -> None: """Starts the bot. Sends a short message detailing what the bot does.""" name = update.effective_user.first_name msg = "You can use me anywhere, @ me in the chatbox and type to get an audio clip." \ " Or just talk to me here and get help from me directly. Type /help to know more." if context.args: msg = "See if you want to tell your nickname and birthday click this --> /tell" logger( message= f"{name} just clicked the button to use /tell in private from {get_chat_name(update)}." ) else: logger(update=update, message=f"/start", command=True) context.bot.send_message(chat_id=update.effective_chat.id, text=msg) del name, msg
def quizizz(update: Update, context: CallbackContext) -> None: """This is called when user calls /quizizz. This sends one physics quiz for the user from the internet.""" logger(update=update, message=f"/quizizz", command=True) context.bot.send_chat_action(chat_id=update.effective_chat.id, action='typing') question, options, answer = quiz_scraper.quiz_maker_v2(number=1) logger(message=f"The question was: {question[0]}\n\n" + '\n'.join(options[0]) + f"\n\nAnswer:{answer[0]}") context.bot.send_poll(chat_id=update.effective_chat.id, question=question[0], options=options[0], is_anonymous=False, type=Poll.QUIZ, correct_option_id=answer[0])
def receive_answer(update: Update, context: CallbackContext) -> None: """ Saves quiz related user data. Runs everytime a user answers a quiz. This data is used later in generating the leaderboard. """ user = update.poll_answer.user chosen_answer = update.poll_answer.option_ids # Get quiz id and correct option id- for quiz in context.bot_data['sent_quizzes']: if quiz.poll.id == update.poll_answer.poll_id: correct_answer = quiz.poll.correct_option_id logger(message=f"tms quiz was answered by {user.first_name}") break else: # Only happens when /quizizz quiz was answered. logger(message=f"/quizizz was answered by {user.first_name}") return assert correct_answer is not None # Storing quiz related user data- if 'quizizz' not in context.bot_data: context.bot_data['quizizz'] = {} if user.id not in context.bot_data['quizizz']: # Note: `answers_wrong` below is only for one quiz. For the next quiz, they are reset. context.bot_data['quizizz'][user.id] = {'answers_right': 0, 'questions_answered': 0, 'answers_wrong': 0} # Update/add entries if changed- lad = context.bot_data['quizizz'][user.id] lad['name'] = get_nick(update, context) lad['profile_pic'] = f"profile_pics/{get_nick(update, context)}.jpg" lad['questions_answered'] += 1 if correct_answer != chosen_answer[0]: # If guy got it wrong lad['answers_wrong'] += 1 else: lad['answers_right'] += 1 context.dispatcher.persistence.flush()
def group(update: Update, context: CallbackContext) -> None: """ Checks for profanity in messages and responds to that. Also checks if the bot was mentioned in the chat, if it was, replies to that message. """ chat_id = update.effective_chat.id text = update.message.text if any(bad_word in text.lower().split() for bad_word in prohibited): query = f"SELECT PROFANE_PROB FROM CHAT_SETTINGS WHERE CHAT_ID={chat_id};" true = connection(query, update) logger( message= f"The query executed on the database was:\n{query}\nand the result was:\n{true=}" ) false = 1 - true if r.choices([0, 1], weights=[ false, true ])[0]: # Probabilities are 0.8 - False, 0.2 - True by default. name = get_nick(update, context) out = f"{r.choice(rebukes)} {name}" context.bot.send_message( chat_id=chat_id, text=out, reply_to_message_id=update.message.message_id) # Sends message logger( message= f"{update.effective_user.first_name} used profane language in {get_chat_name(update)}." f"\nThe rebuke by the bot was: '{out}'.") elif context.bot.name in text: # If username was mentioned in group chat, reply to it. shanifier(update, context, is_group=True, the_id=update.message.message_id) del chat_id, text
def before_all(context): context.log = logger() context.log.info('') context.log.info(' (START)') context.unit = UnitHelper(context) context.zmq = ZMQHelper() context.statsd = StatsdMock() context.statsd.start() context.zmq.start() context.unit.configure() context.unit.download()
def bday_add_or_update(update: Update, context: CallbackContext) -> int: # INPUT """Changes or adds the user's birthday into our records.""" bday_date = update.message.text try: dt_obj = datetime.datetime.strptime(bday_date, "%Y-%m-%d") except Exception as e: # If user didn't enter birthday in the right format logger(message=f"The traceback is: {e}", warning=True) wrong(update, context) # Asks for a valid input else: name = get_nick(update, context) context.user_data['birthday'] = dt_obj context.bot.send_message(chat_id=update.effective_chat.id, text=f"Ok {name}, I'll remember your birthday like you say.", reply_markup=markup) logger(message=f"{update.effective_user.first_name} just changed their birthday to {bday_date}.") return CHOICE
def helper(update: Update, context: CallbackContext) -> None: """Sends a message to the user which explains how to use the bot.""" buttons = [[ InlineKeyboardButton(text="Try out inline mode", switch_inline_query_current_chat="") ], [ InlineKeyboardButton( text="Use inline mode in another chat", switch_inline_query="") ]] markup = InlineKeyboardMarkup(buttons) context.bot.send_message( chat_id=update.effective_chat.id, text= r"This bot sends you audio clips straight from the Shani Sir Module\. " "He's savage when he's cranky\." "\n\nHow to get clips \(Inline mode\):" "\n@ me in the chatbox \(don't press send yet\!\), press space and then type" r" to get a clip\." "\n\nCommands available:" "\n/help \- This will literally just send this message again\." "\n/start \- Starts the bot in private chat\." "\n/swear \- Teaches you not to swear\." "\n/snake \- Sends you a roast\." "\n/facts \- Blesses you with an incredibly useful fact\." "\n/8ball \- Answers yes/no questions in Shani Sir style\!" "\n/settings \- Modify my behaviour with granular precision\." "\n/quizizz \- Sends you a physics question\." "\n\nHow to use /8ball:\nReply to a message with /8ball\nor send /8ball in" " chat and reply to the message the bot sends\.\n\n" r"Inspired by the [Shani Sir Module](https://github.com/tmslads/Shanisirmodule)" r" and Telegram\!", parse_mode="MarkdownV2", disable_web_page_preview=True, reply_markup=markup) logger(update=update, message=f"/help", command=True)
def initiate(update: Update, context: CallbackContext) -> int: # Entry_point """This function is called when user uses /tell. It branches into 3- 'birthday', 'nickname' and 'nothing'.""" chat = update.effective_chat first_name = update.effective_user.first_name if chat.type != "private": link = create_deep_linked_url(bot_username=context.bot.username, payload="tell") tell_markup = InlineKeyboardMarkup( [[InlineKeyboardButton(text="Let's go like you say!", url=link)]]) context.bot.send_message( chat_id=chat.id, text="Just come to another chat I want to talk to you like you say", reply_markup=tell_markup) logger( message=f"{first_name} just tried using /tell in a {chat.type}. " f"A message telling them to use it in private was sent.") del chat, first_name, link, tell_markup return -1 name = get_nick(update, context) context.bot.send_message( chat_id=chat.id, text= f'What do you want to tell me {name}? Type /cancel anytime to switch me off', reply_to_message_id=update.message.message_id, reply_markup=markup) logger(message=f"/tell", update=update, command=True) del name return CHOICE
def before_all(context): context.log = logger() context.log.info('') context.log.info(' (START)') context.tokens = dict() context.unit = UnitHelper(context) context.zmq = ZMQHelper(context) context.fio = FioMock(context) context.ledger = LedgerMock(context) context.vault = VaultMock(context) context.statsd = StatsdMock() context.statsd.start() context.fio.start() context.ledger.start() context.vault.start() context.zmq.start() context.unit.configure() context.unit.download()