def handle_getfighter(self, chat, attr): """Handles command /getfighter Gives all information about a specific fighter Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /getfighter* Where * is any string. The use of this command is: Option 1. /getfighter [username] * Will show info about username (rest of args ignored) Option 2. /getfighter Will prompt button GUI with all fighters, selecting one of them or sending a message with the name of a fighter will do the same effect as Option 1 with the same fighter """ items = [] for fighter in self.bot.get_fighters_extended(): items.append(fighter["username"]) if len(attr) > 0: if attr[0] in items: text = "👤 Fighter: *" + attr[0] + "*\n" \ + "\Status: " fighter = next(item for item in self.bot.get_fighters_extended() if item["username"] == attr[0]) if fighter["alive"]: text += " alive" else: text += " dead 💀" text += "\nHas killed: " if len(fighter["killed"]) > 0: text += ', '.join("`" + fighter["killed"] + "`") else: text += "no other fighters" text += "\nShow in list: " if fighter['show']: text += "yes" else: text += "no 👻" else: text = "Fighter not found." self.ask_status = "NONE" items = [] else: text = "Insert the name of the fighter, or use the buttons prompted." self.ask_status = "BUTTONS_GETFIGHTER" keyboard = self.build_keyboard(items) self.send_message(text, chat, keyboard) log.send_message("Telegram - sent WarBotAdmin.handle_getfighter")
def handle_getfighters(self, chat): """Handles command /getfighters Gives list of fighters Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /getfighters* Where * is any string """ text = '👥 *List of fighters:*' i = 0 for fighter in self.bot.get_fighters_extended(): text += "\n" + str(i + 1) + ". `" + fighter["username"] + "`" if not fighter["alive"]: text += " 💀" if not fighter["show"]: text += " 👻" i += 1 if i % 5 == 0: self.send_message(text, chat) text = "" if text != "": self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_getfighters")
def handle_addcandidate(self, chat, attr): """Handles command /addcandidate Adds one or more candidates Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /addcandidate* Where * is any string. The use of this command is: /addcandidate [user1] [user2] ... (again, nothing else to say) """ text = "" if len(attr) > 0: for username in attr: result = self.bot.add_candidate(username) if result: text += "Candidate *" + username + "* has been added.\n" else: text += "Candidate *" + username + "* is already on the candidates list.\n" else: text = "You did not insert the candidate to add." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_addcandidate")
def handle_getcandidates(self, chat): """Handles command /getcandidates Gives list of candidates Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /getcandidates* Where * is any string """ text = '🕵️ *List of candidates:*' i = 0 for candidate in self.bot.get_candidates(): text += "\n" + str(i + 1) + ". `" + candidate + "`" i += 1 if i % 5 == 0: self.send_message(text, chat) text = "" if text != "": self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_getcandidates")
def handle_restart(self, chat, attr): """Handles command /restart Restarts database Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /restart* Where * is any string. The database will be restarted iff the comand is followed by the "confirm" keyword """ do_restart = False if len(attr) > 0: if attr[0] == "confirm": do_restart = True if do_restart: result = self.bot.restart() if result: text = "Database has been restarted." else: text = "Database could not be restarted." else: text = "To do this, you must confirm this action. Have in " \ + "consideration this action is irreversible. TO confirm, " \ + "use /restart `confirm`." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_restart")
def download_profilepic(self, username, filename): """Download username's profile picture Parameters ---------- username : str Twitter username whose picture wants to be downloaded filename : str Filename where picture will be saved Return ------ Option 1: str File route to the downloaded pic Option 2: None In case download could not be done """ file_download_route = route.paste(self.images_route, filename) try: url = self.api.get_user( screen_name=username).profile_image_url_https.replace( '_normal', '') urllib.request.urlretrieve(url, file_download_route) return file_download_route except Exception as e: log.send_message("[TWITTER API] ERROR - at api.get_user -> " + str(e)) return None
def setup_vars(self): Vars = Query() if len(self.db_vars.search(Vars.varname == 'last_seen_id')) == 0: self.db_vars.insert({'varname': 'last_seen_id', 'value': 1}) if len(self.db_vars.search(Vars.varname == 'optin_running')) == 0: self.db_vars.insert({'varname': 'optin_running', 'value': False}) if len(self.db_vars.search(Vars.varname == 'next_battle_year')) == 0: self.db_vars.insert({'varname': 'next_battle_year', 'value': 2000}) if len(self.db_vars.search(Vars.varname == 'next_battle_month')) == 0: self.db_vars.insert({'varname': 'next_battle_month', 'value': 12}) if len(self.db_vars.search(Vars.varname == 'next_battle_day')) == 0: self.db_vars.insert({'varname': 'next_battle_day', 'value': 19}) if len(self.db_vars.search(Vars.varname == 'next_battle_hour')) == 0: self.db_vars.insert({'varname': 'next_battle_hour', 'value': 0}) if len(self.db_vars.search(Vars.varname == 'next_battle_minute')) == 0: self.db_vars.insert({'varname': 'next_battle_minute', 'value': 0}) if len(self.db_vars.search(Vars.varname == 'battle_frequency_hours')) == 0: self.db_vars.insert({'varname': 'battle_frequency_hours', 'value': 6}) if len(self.db_vars.search(Vars.varname == 'battle_frequency_minutes')) == 0: self.db_vars.insert({'varname': 'battle_frequency_minutes', 'value': 0}) if len(self.db_vars.search(Vars.varname == 'stop_frequency')) == 0: self.db_vars.insert({'varname': 'stop_frequency', 'value': True}) if len(self.db_vars.search(Vars.varname == 'stop_next_battle')) == 0: self.db_vars.insert({'varname': 'stop_next_battle', 'value': True}) if len(self.db_vars.search(Vars.varname == 'fighter_announce')) == 0: self.db_vars.insert({'varname': 'fighter_announce', 'value': False}) if len(self.db_vars.search(Vars.varname == 'announce_queue')) == 0: self.db_vars.insert({'varname': 'announce_queue', 'value': []}) if len(self.db_vars.search(Vars.varname == 'battle_queue')) == 0: self.db_vars.insert({'varname': 'battle_queue', 'value': []}) if len(self.db_vars.search(Vars.varname == 'message_queue')) == 0: self.db_vars.insert({'varname': 'message_queue', 'value': []}) log.send_message("[DATABASE] Update: done setup_vars")
def change_fighter_show(self, username, show): User = Query() self.db_fighters.update({'show': show}, User.username == username) if show: log.send_message("[DATABASE] Update: " + username + " is now showed") else: log.send_message("[DATABASE] Update: " + username + " is now hidden")
def change_fighter_alive(self, username, alive): User = Query() self.db_fighters.update({'alive': alive}, User.username == username) if alive: log.send_message("[DATABASE] Update: " + username + " is now alive") else: log.send_message("[DATABASE] Update: " + username + " is now dead")
def handle_forcebattle(self, chat, attr): """Handles command /forcebattle Forces a battle, either randomly or between two specific users Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /forcebattle* Where * is any string. The use of this command is: /forcebattle (winner) (defeated) - if there are not 2 args, it forces a random battle - if both winner and defeated, winner defeats defeated """ if len(attr) >= 2: winner = attr[0] defeated = attr[1] result = self.bot.force_battle(winner, defeated) if result: text = 'Battle executed: *' + winner + '* has killed *' + defeated + '*' else: text = "Battle could not be executed." else: winner, defeated = self.bot.battle() if winner != None and defeated != None: text = 'Battle executed: *' + winner + '* has killed *' + defeated + '*' else: text = 'Battle could not be executed.' self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_forcebattle")
def send_newfighter(self, username): """Send new fighter message to Twitter Sends new fighter message, including image """ # generate filenames img = username + "_profilepic.png" img_route = self.api.download_profilepic(username, img) out = "newfighter-" + username + ".png" out_route = self.imgh.generate_newfighter(img, out) # post tweet try: self.api.post_tweet("We have a new fighter! " + \ "@{}, welcome to the battle!".format(username), [out_route]) log.send_message("[TWITTER] Tweet posted: new fighter " + username) self.bot.add_message_queue("🛎️ Tweet posted: new fighter " \ + "*{}*".format(username)) except Exception as e: log.send_message("[TWITTER] Tweet COULD NOT be posted: new fighter " \ + username + " -> " + str(e)) self.bot.add_message_queue("⚠️ Tweet could not be posted: new " \ + "fighter *{}*".format(username)) # remove images generated os.remove(img_route) os.remove(out_route)
def update_next_battle(self, date): Vars = Query() self.db_vars.update({'value': date.year}, Vars.varname == 'next_battle_year') self.db_vars.update({'value': date.month}, Vars.varname == 'next_battle_month') self.db_vars.update({'value': date.day}, Vars.varname == 'next_battle_day') self.db_vars.update({'value': date.hour}, Vars.varname == 'next_battle_hour') self.db_vars.update({'value': date.minute}, Vars.varname == 'next_battle_minute') log.send_message("[DATABASE] Update: next_battle set to {}/{}/{} {}:{}".format(date.year, date.month, date.day, date.hour, date.minute))
def insert_candidate(self, username): # Check if candidate is already in the database Candidate = Query() if len(self.db_candidates.search(Candidate.username == username)) > 0: log.send_message("[DATABASE] Insertion error: Candidate " + username + " is already on the database") else: new_candidate = {'username': username} self.db_candidates.insert(new_candidate) log.send_message("[DATABASE] Insertion: Candidate " + username + " added to the database")
def handle_help(self, chat): """Handles command /help Outputs help message. Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /help* Where * is any string """ text = "*Bloomgogo War Bot* v1.0\n" \ + "Created by: Miguel Ángel Fernández Gutiérrez (@mianfg)\n\n" \ + "*Commands 👩💻👨💻*\n" \ + "\n🔁 Sync:\n" \ + "/runoptin · Allows Twitter users to add themselves to the "\ + "candidates list 📬 mentioning the account\n" \ + "/stopoptin · Stops previous functionality 📭\n" \ + "\n⚔️ Batallas:\n" \ + "/nextbattle · Information about when the next battle will " \ + "happen ⏰\n" \ + "/schedulebattle `[dd/mm/aaaa hh:mm | hh:mm | stop]` · " \ + "Configures when next battle will happen ➡️⏰\n" \ + "— `dd.mm.aaaa hh:mm` · Specify day and hour\n" \ + "— `hh:mm` · Specify hour (if passed, tomorrow will be assigned)\n" \ + "— `stop` · Stop battles 🛑⏰\n" \ + "/battlefrequency · Returns frequency in which battles will be programmed ⏳\n" \ + "/setbattlefrequency `[hours] [minutes]` · Configures frequency in which battles will be programmed ➡️⏳\n" \ + "/stopfrequency · Stop automatic battles 🛑⏳\n" \ + "/forcebattle `(winner) (defeated)` · Force a battle ➡️⚔️\n" \ + "— `winner` · Fighter that will win the battle\n" \ + "— `defeated` · Fighter that will lose the battle\n" \ + "— leave blank to inquire a random battle\n" \ + "**Important notice:** _when adding usernames, do not include @_\n" \ + "\nℹ️ Information and status:\n" \ + "/getfighters · Returns a complete list of fighters, including their state in the game 👥\n" \ + "/getfighter `[username]` · Return all information about a fighter 👥\n" \ + "/getcandidates · Return complete list of candidates 🕵️\n" \ + "\n➡️👥 Alter users:\n" \ + "/addfighter `[username](!)` · Add a fighter\n" \ + "— `!` · Add the sign `!` to publish a tweet announcing that the user has been added to the game as fighter 🔔\n" \ + "/deletefighter `[username]` · Delete a fighter (use with caution!)\n" \ + "/addcandidate `[username]` · Add a candidate\n" \ + "/deletecandidate `[username]` · Delete a candidate (use with caution!)\n" \ + "/revive `[username]` · Revive a fighter 🧟\n" \ + "\nInteractivity:\n" \ + "/announcefighters · Automatically announce added fighters 🔔\n" \ + "/stopannouncefighters · New fighters will be announced only if specified when adding 🛑🔔\n" \ + "\n📈 Estado:\n" \ + "/status · Retrieve bot status\n" \ + "/restart `confirm` · Restart database" self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_help")
def handle_unauthorized(self, chat): """Handles message sent by unauthorized user Sends a message to unauthorized user that interacts with the Telegram bot """ text = "Hi! This bot has been designed to be manipulated by a restrained " \ + "set of users. Talk with this bot's administrator for more info." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_unauthorized")
def insert_fighter_kill(self, username, killed): User = Query() new_killed = self.db_fighters.search(User.username == username) if len(new_killed) > 0: new_killed = new_killed[0]['killed'] else: log.send_message("[DATABASE] Update error: No ocurrences of " + username + " found trying to kill " + killed) if not killed in new_killed: new_killed.append(killed) self.db_fighters.update({'killed': new_killed}, User.username == username) log.send_message("[DATABASE] Update: " + username + " killed " + killed)
def insert_fighter(self, username, alive=True): # Check if fighter is already in the database User = Query() if len(self.db_fighters.search(User.username == username)) > 0: log.send_message("[DATABASE] Insertion error: fighter " + username + " is already on the database") else: new_fighter = {'username': username, 'alive': alive, 'killed': [], 'show': True} self.db_fighters.insert(new_fighter) log.send_message("[DATABASE] Insertion: fighter " + username + " added to the database") # Delete from candidates self.delete_candidate(username)
def handle_status(self, chat): """Handles command /status Sends back bot status Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /status* Where * is any string """ text = "- Number of fighters: " text += str(len(self.bot.get_fighters())) text += " ({} 💀)\n".format(str(len(self.bot.get_dead_fighters()))) text += "- Number of candidates: " text += str(len(self.bot.get_candidates())) text += "\n- Opt-in: " if self.bot.get_optin_running(): text += "activated\n" else: text += "deactivated\n" text += "- Next battle: " if self.bot.get_stop_next_battle(): text += "won't be\n" else: date = self.bot.get_next_battle() text += "{}/{}/{} {:02d}:{:02d}\n".format(date.day, date.month, date.year, date.hour, date.minute) text += "- Battle frequency: " f_h, f_m = self.bot.get_battle_frequency() text += "{} hours {} minutes\n".format(f_h, f_m) text += "- Frequency active: " if self.bot.get_stop_frequency(): text += "no\n" else: text += "yes\n" text += "- Fighter announce: " if self.bot.get_fighter_announce(): text += "automatic\n" else: text += "manual\n" self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_status")
def optin(self): """Executes opt-in functionality """ try: mentions = self.api.get_mentions() for mention in mentions: username = mention.user.screen_name self.bot.add_candidate(username) log.send_message("[TWITTER] Mentions caught") except Exception as e: log.send_message("[TWITTER] Mentions could not be caught -> " + str(e))
def main(self): last_update_id = None while True: updates = self.get_updates(last_update_id) try: if len(updates["result"]) > 0: last_update_id = self.get_last_update_id(updates) + 1 self.handle_updates(updates) except KeyError: log.send_message( "[TELEGRAM API] Keyerror was produced. Retrying...") self.update_message_queue() self.message_queue() time.sleep(self.sleep_time)
def handle_start(self, chat): """Handles command /starts Sends start message Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /send* Where * is any string """ text = 'Welcome to *Bloomgogo War Bot*! Use /help for more information' self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_start")
def handle_deletecandidate(self, chat, attr): """Handles command /deletecandidate Deletes one or more candidates Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /deletecandidate* Where * is any string. The use of this command is: Option 1. /deletecandidate [user1] [user2] ... Will delete the candidates passed as args Option 2. /deletecandidate Will display button GUI with candidates """ items = [] text = "" if len(attr) > 0: for username in attr: result = self.bot.delete_candidate(username) if result: text += "Candidate *" + username + "* has been deleted.\n" else: text += "Candidate *" + username + "* not found, therefore cannot be deleted.\n" self.ask_status = "NONE" else: items = self.bot.get_candidates() text = "Insert the name of the candidate to delete, or use the buttons prompted." self.ask_status = "BUTTONS_DELETECANDIDATE" keyboard = self.build_keyboard(items) self.send_message(text, chat, keyboard) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_deletecandidate")
def handle_schedulebattle(self, chat, attr): """Handles command /schedulebattle Schedules when next battle will happen Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /schedulebattle* Where * is any string. The use of this command is: /schedulebattle [dd/mm/aaaa hh:mm | hh:mm | stop] - dd/mm/aaaa hh:mm · exact date - hh:mm · next hour - stop · stops battle scheduling """ input = ' '.join(attr) result = self.bot.set_next_battle(input) if input.startswith('stop'): text = "Next battle has successfully been stopped. " self.bot.set_stop_next_battle(True) else: if result: text = "Successfully modified. " self.bot.set_stop_next_battle(False) else: text = "Not modified, wrong format. You must insert the date in the format dd/mm/yy HH:MM. " if not self.bot.get_stop_next_battle(): date = self.bot.get_next_battle() text += "Next battle is scheduled to happen at: " \ + "{}/{}/{} {:02d}:{:02d}".format(date.day, date.month, date.year, date.hour, date.minute) else: text += "There will be no next battle." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_schedulebattle")
def handle_revive(self, chat, attr): """Handles command /revive Revives one or more fighters Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /revive* Where * is any string. The use of this command is: /revive [user1] [user2] ... (this is getting a little repetitive...) """ items = [] text = "" if len(attr) > 0: for username in attr: result = self.bot.revive_fighter(username) if result: text = "Fighter *" + username + "* has been revived. 🧟\n" else: text = "We could not revive *" + username + "*: not found or already alive.\n" self.ask_status = "NONE" else: items = self.bot.get_dead_fighters() text = "Insert the name of the fighter to revive, or use the buttons prompted." self.ask_status = "BUTTONS_REVIVE" keyboard = self.build_keyboard(items) self.send_message(text, chat, keyboard) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_revive")
def get_mentions(self): """Gets mentions from Twitter bot's account Returns ------- list<Status># WIP check if this is the class, or it is not Status List of mentions """ last_seen_id = self.db.get_last_seen_id() try: mentions = self.api.mentions_timeline(last_seen_id, tweet_mode='extended') if len(mentions) > 0: self.db.update_last_seen(mentions[0].id) return reversed(mentions) except Exception as e: log.send_message( "[TWITTER API] ERROR - at api.mentions_timeline() -> " + str(e)) return []
def handle_stopoptin(self, chat): """Handles command /stopoptin Stops opt-in (if it was not stopped before) Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /stopoptin* Where * is any string """ if not self.bot.get_optin_running(): text = "Opt-in was already stopped." else: self.bot.set_optin_running(False) text = "Opt-in successfully deactivated." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_stopoptin")
def handle_stopfrequency(self, chat): """Handles command /stopfrequency Stops battle frequency. See `handle_battlefrequency` for more info. Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /stopfrequency* Where * is any string """ if self.bot.get_stop_frequency(): text = "Automatic battles were alredy stopped. To resume, use /setbattlefrequency." else: self.bot.set_stop_frequency(True) text = "Automatic battles have successfully been stopped. To resume, use /setbattlefrequency." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_stopfrequency")
def handle_announcefighters(self, chat): """Handles command /announcefighters Activate announcing new fighters in Twitter automatically Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /announcefighters* Where * is any string """ if self.bot.get_fighter_announce(): text = "Fighters are being announced by default. To deactivate, use /stopannouncefighters." else: self.bot.set_fighter_announce(True) text = "From now on, new fighters will be announced by default." self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_announcefighters")
def handle_nextbattle(self, chat): """Handles command /nextbattle Returns when next battle will happen. Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /nextbattle* Where * is any string """ if self.bot.get_stop_next_battle(): text = "There will be no next battle. Use /schedulebattle to configure it." else: date = self.bot.get_next_battle() text = "Next battle is scheduled to happen at: " \ + "{}/{}/{} {:02d}:{:02d}".format(date.day, date.month, date.year, date.hour, date.minute) self.send_message(text, chat) log.send_message("[TELEGRAM] sent WarBotAdmin.handle_nextbattle")
def handle_setbattlefrequency(self, chat, attr): """Handles command /setbattlefrequency Sets battle frequency. See `handle_battlefrequency` for more info. Command call ------------ This function is called whenever the authorized user sends a message to the Telegram bot of the form: /setbattlefrequency* Where * is any string. The use of this command is: /setbattlefrequency [hours] [minutes] (pretty self-explanatory...) """ if len(attr) == 2: try: h = int(attr[0]) m = int(attr[1]) if h >= 0 and m > 0 and m < 60: self.bot.set_battle_frequency(attr[0], attr[1]) self.bot.set_stop_frequency(False) text = "Battle frequency successfully set to {} hours {} minutes.".format( h, m) else: text = "You must insert a valid amount of hours and minutes." except ValueError: text = "You must insert a valid amount of hours and minutes." else: text = "Wrong number of arguments." self.send_message(text, chat) log.send_message( "[TELEGRAM] sent WarBotAdmin.handle_setbattlefrequency")