def plpaste(text, message, bot): """<command> - pastes the plugin file that contains <command>.""" if text in bot.plugin_manager.commands: file_path = bot.plugin_manager.commands[text].plugin.file_path with open(file_path) as f: message(web.paste(f.read(), ext='py')) elif text + ".py" in listdir('plugins/'): with open('plugins/{}.py'.format(text)) as f: message(web.paste(f.read(), ext='py')) else: return "Could not find specified plugin."
def test_paste(mock_requests): mock_requests.add( mock_requests.POST, "https://hastebin.com/documents", json={"key": "foobar"}, ) from cloudbot.util import web assert (web.paste("test data", service="hastebin") == "https://hastebin.com/foobar.txt") assert web.paste("test data", service="none") == "Unable to paste data"
def on_hook_end(error, launched_hook, launched_event, admin_log): should_broadcast = True if error is not None: messages = [ "Error occurred in {}.{}".format(launched_hook.plugin.title, launched_hook.function_name) ] try: lines = traceback.format_exception(*error) last_line = lines[-1] messages.append(last_line.strip()) except Exception: msg = traceback.format_exc()[-1] messages.append("Error occurred while formatting error {}".format(msg)) else: try: url = web.paste('\n'.join(lines)) messages.append("Traceback: " + url) except Exception: msg = traceback.format_exc()[-1] messages.append("Error occurred while gathering traceback {}".format(msg)) try: lines = ["{} = {}".format(k, v) for k, v in _dump_attrs(launched_event)] exc_type, exc, exc_tb = error lines.append("") lines.append("Error data:") lines.extend("{} = {}".format(k, v) for k, v in _dump_attrs(exc)) if isinstance(exc, RequestException): if exc.request is not None: req = exc.request lines.append("") lines.append("Request Info:") lines.extend("{} = {}".format(k, v) for k, v in _dump_attrs(req)) if exc.response is not None: response = exc.response lines.append("") lines.append("Response Info:") lines.extend("{} = {}".format(k, v) for k, v in _dump_attrs(response)) url = web.paste('\n'.join(lines)) messages.append("Event: " + url) except Exception: msg = traceback.format_exc()[-1] messages.append("Error occurred while gathering error data {}".format(msg)) for message in messages: admin_log(message, should_broadcast)
def plpaste(text, bot): """<command> - pastes the plugin file that contains <command> :type text: str :type bot: cloudbot.bot.CloudBot """ if text in bot.plugin_manager.commands: file_path = bot.plugin_manager.commands[text].plugin.file_path with open(file_path) as f: return web.paste(f.read(), ext='py') elif text + ".py" in listdir('plugins/'): with open('plugins/{}.py'.format(text)) as f: return web.paste(f.read(), ext='py') else: return "Could not find specified plugin."
def test_paste_error(mock_requests): from cloudbot.util import web assert web.paste('test data') == 'Unable to paste data' mock_requests.add(mock_requests.POST, 'https://hastebin.com/documents', status=502) assert web.paste('test data') == 'Unable to paste data' mock_requests.replace(mock_requests.POST, 'https://hastebin.com/documents', json={'message': 'Error'}, status=201) assert web.paste('test data') == 'Unable to paste data'
def eval_py(code, paste_multiline=True): attempts = 0 while True: try: output = http.get("http://eval.appspot.com/eval", statement=code).rstrip('\n') # sometimes the API returns a blank string on first attempt, lets try again # and make sure it is actually supposed to be a blank string. ._. if output == "": output = http.get("http://eval.appspot.com/eval", statement=code).rstrip('\n') break except http.HTTPError: if attempts > 2: return "Failed to execute code." else: attempts += 1 continue if "Traceback (most recent call last):" in output: status = "Python error: " else: status = "Code executed successfully: " if "\n" in output and paste_multiline: return status + web.paste(output, 'py') else: return output
def dumpusers(conn): """- Dumps all stored user data for this connection to the console :type conn: cloudbot.client.Client """ data = get_users(conn) return web.paste(MappingSerializer().serialize(data, indent=2))
def get_sound_info(game, search): search = search.replace(" ", "+") try: data = http.get_json("http://p2sounds.blha303.com.au/search/%s/%s?format=json" % (game, search)) except urllib.error.HTTPError as e: return "Error: " + json.loads(e.read())["error"] items = [] for item in data["items"]: if "music" in game: textsplit = item["text"].split('"') text = "" for i in range(len(textsplit)): if i % 2 != 0 and i < 6: if text: text += " / " + textsplit[i] else: text = textsplit[i] else: text = item["text"] items.append("{} - {} {}".format(item["who"], text if len(text) < 325 else text[:325] + "...", item["listen"])) if len(items) == 1: return items[0] else: return "{} (and {} others: {})".format(items[0], len(items) - 1, web.paste("\n".join(items)))
def listdetailedfactoids(chan): """- lists all available factoids with their respective data""" headers = ("Command", "Output") data = [(FACTOID_CHAR + fact[0], fact[1]) for fact in sorted(factoid_cache[chan].items())] table = gen_markdown_table(headers, data).encode('UTF-8') return web.paste(table, "md", "hastebin")
def hookstats(text, bot, notice_doc): """{global|network <name>|channel <network> <channel>|hook <hook>} - Get hook usage statistics""" args = text.split() stats_type = args.pop(0).lower() data = get_stats(bot) try: handler, arg_count = stats_funcs[stats_type] except LookupError: notice_doc() return if len(args) < arg_count: notice_doc() return headers, data = handler(data, *args[:arg_count]) if not data: return "No stats available." table = gen_markdown_table(headers, data) return web.paste(table, 'md', 'hastebin')
def currency_list(): currencies = sorted(set( (obj["symbol"], obj["id"]) for obj in api.currencies), key=itemgetter(0)) lst = ['{: <10} {}'.format(symbol, name) for symbol, name in currencies] lst.insert(0, 'Symbol Name') return "Available currencies: " + web.paste('\n'.join(lst))
def test_paste_error(mock_requests): from cloudbot.util import web assert web.paste("test data") == "Unable to paste data" mock_requests.add(mock_requests.POST, "https://hastebin.com/documents", status=502) assert web.paste("test data") == "Unable to paste data" mock_requests.replace( mock_requests.POST, "https://hastebin.com/documents", json={"message": "Error"}, status=201, ) assert web.paste("test data") == "Unable to paste data"
def on_hook_end(error, launched_hook, launched_event, admin_log): if error is None: return should_broadcast = True messages = [ "Error occurred in {}.{}".format(launched_hook.plugin.title, launched_hook.function_name) ] try: lines = traceback.format_exception(*error) last_line = lines[-1] messages.append(last_line.strip()) except Exception: msg = traceback.format_exc()[-1] messages.append("Error occurred while formatting error {}".format(msg)) else: try: url = web.paste('\n'.join(lines)) messages.append("Traceback: " + url) except Exception: msg = traceback.format_exc()[-1] messages.append( "Error occurred while gathering traceback {}".format(msg)) try: lines = ["Event Data:"] lines.extend(indent(format_attrs(launched_event))) _, exc, _ = error lines.append("") lines.append("Error data:") lines.extend(indent(format_error_chain(exc))) url = web.paste('\n'.join(lines)) messages.append("Event: " + url) except Exception: msg = traceback.format_exc()[-1] messages.append( "Error occurred while gathering error data {}".format(msg)) for message in messages: admin_log(message, should_broadcast)
def currency_list(): """- List all available currencies from the API""" currency_map = api.get_crypto_currency_map() currencies = sorted(set( (obj.symbol, obj.name) for obj in currency_map.data), key=itemgetter(0)) lst = ["{: <10} {}".format(symbol, name) for symbol, name in currencies] lst.insert(0, "Symbol Name") return "Available currencies: " + web.paste("\n".join(lst))
def listignores(db, conn, chan): """- List all active ignores for the current channel""" rows = db.query(ignores) \ .filter(ignores.conn == conn.name.lower()) \ .filter(ignores.chan == chan.lower()) \ .all() out = '\n'.join(row.mask for row in rows) + '\n' return web.paste(out)
def pluginlist(bot): """- List all currently loaded plugins""" manager = bot.plugin_manager plugins = [ (plugin.title, str(Path(plugin.file_path).resolve().relative_to(bot.base_dir))) for plugin in manager.plugins.values() ] plugins.sort(key=itemgetter(0)) table = gen_markdown_table(["Plugin", "Path"], plugins) return web.paste(table, service="hastebin")
def update(): repo = Repo() git = repo.git try: pull = git.pull() except Exception as e: return e if "\n" in pull: return web.paste(pull) else: return pull
def get_thread_dump(): code = [] threads = [(get_name(thread_id), traceback.extract_stack(stack)) for thread_id, stack in sys._current_frames().items()] for thread_name, stack in threads: code.append("# {}".format(thread_name)) for filename, line_num, name, line in stack: code.append("{}:{} - {}".format(filename, line_num, name)) if line: code.append(" {}".format(line.strip())) code.append("") # new line return web.paste("\n".join(code), ext='txt')
def python(text): """<python code> - executes <python code> using eval.appspot.com""" output = web.pyeval(text, pastebin=False) if '\n' in output: if 'Traceback (most recent call last):' in output: status = 'Error: ' else: status = 'Success: ' return status + web.paste(output) else: return output
def listignores(db, conn, chan): """- List all active ignores for the current channel""" rows = db.execute( select([table.c.mask], and_( table.c.connection == conn.name.lower(), table.c.channel == chan.lower(), ))).fetchall() out = '\n'.join(row['mask'] for row in rows) + '\n' return web.paste(out)
def list_optout(conn, event, async_call): """[channel] - View the opt out data for <channel> or the current channel if not specified. Specify "global" to view all data for this network :type conn: cloudbot.clients.irc.Client :type event: cloudbot.event.CommandEvent """ chan, allowed = yield from check_global_perms(event) if not allowed: return opts = yield from async_call(get_channel_optouts, conn.name, chan) table = yield from async_call(format_optout_list, opts) return web.paste(table, "md", "hastebin")
def python(text): """<python code> - executes <python code> using eval.appspot.com""" return "This API has been deprecated and removed." output = yield from web.pyeval(text, pastebin=False) if '\n' in output: if 'Traceback (most recent call last):' in output: status = 'Error: ' else: status = 'Success: ' return status + web.paste(output) else: return output
def bungeesec(reply, text, nick, notice): if getTokens(nick) < 15000: notice( "You don't have enough tokens to do a bungeesecure (15000 needed)... Help a little more !" ) return None if not text: reply("Please specify an IP address/ dns ! !bungeesecure IP") takeTokens(2000, nick, notice) IP = text timeout = float((float(pingavg(IP)) / 100) + 0.1) socket.setdefaulttimeout(timeout) notice("I'm scanning with a timeout of " + str(timeout)) reply("Scanning ports... Please wait a moment !") toreply = "List of minecraft servers found for : " + str(IP) + ":\n" start = 20000 end = 40000 scan = Scanner() scan.open = [] scan.host = IP scan.ports = list(range(start, end)) serversPorts = scan.start() others = [] for port in serversPorts: mcinf = pingmc(IP, port) if mcinf: toreply += "Server found on port " + str(port) + " : " + str( mcinf) + "\n" else: others.append(port) if others: toreply += "Other(s) open ports found, but that don't seems to have a minecraft server on them :" + str( others) if len(serversPorts) == 0: toreply += "No servers found. Check the entered IP address." if len(serversPorts) < 5: return toreply else: return web.paste( strip_all(toreply).encode("latin-1", errors='replace'))
def list_langs(message): """List the languages/codes that can be used to translate. Translation is powered by Yandex https://translate.yandex.com""" url = api_url + "getLangs" params = {'key': api_key, 'ui': 'en'} r = requests.get(url, params=params) data = r.json() langs = data['langs'] out = "Language Codes:" out += ",".join("\n{}-{}".format(key, value) for (key, value) in sorted(langs.items(), )) out += "\n\nTranslation directions:" out += ",".join("\n{}".format(code) for code in data['dirs']) paste = web.paste(out, ext="txt") return "Here is information on what I can translate as well as valid language codes. {}".format( paste)
def friends(text, chan, conn, db): """Prints a list of the top monster friends in the channel, if 'global' is specified all channels in the database are included.""" if chan in opt_out: return friends = defaultdict(int) chancount = defaultdict(int) out = "" if text.lower() == 'global' or text.lower() == 'average': out = "Monster friend scores across the network: " scores = db.execute(select([table.c.name, table.c.befriend]) \ .where(table.c.network == conn.name) \ .order_by(desc(table.c.befriend))) if scores: for row in scores: if row[1] == 0: continue chancount[row[0]] += 1 friends[row[0]] += row[1] if text.lower() == 'average': for k, v in friends.items(): friends[k] = int(v / chancount[k]) else: return "it appears no one has friended any monsters yet." else: out = "Monster friend scores in {}: ".format(chan) scores = db.execute(select([table.c.name, table.c.befriend]) \ .where(table.c.network == conn.name) \ .where(table.c.chan == chan.lower()) \ .order_by(desc(table.c.befriend))) if scores: for row in scores: if row[1] == 0: continue friends[row[0]] += row[1] else: return "it appears no one has friended any monsters yet." topfriends = sorted(friends.items(), key=operator.itemgetter(1), reverse=True) url = web.paste(json.dumps(topfriends, indent=4)) out += ' • '.join([ "{}: {}".format('\x02' + k[:1] + u'\u200b' + k[1:] + '\x02', str(v)) for k, v in topfriends ]) out = smart_truncate(out) out += " " + url return out
def list_langs(message): """List the languages/codes that can be used to translate. Translation is powered by Yandex https://translate.yandex.com""" url = api_url + "getLangs" params = { 'key':api_key, 'ui':'en' } r = requests.get(url, params=params) data = r.json() langs = data['langs'] out = "Language Codes:" out += ",".join("\n{}-{}".format(key, value) for (key, value) in sorted(langs.items(), )) out += "\n\nTranslation directions:" out += ",".join("\n{}".format(code) for code in data['dirs']) paste = web.paste(out, ext="txt") return "Here is information on what I can translate as well as valid language codes. {}".format(paste)
def bungeesec(reply, text, nick, notice): if getTokens(nick) < 15000: notice("You don't have enough tokens to do a bungeesecure (15000 needed)... Help a little more !") return None if not text: reply("Please specify an IP address/ dns ! !bungeesecure IP") takeTokens(2000, nick, notice) IP = text timeout = float((float(pingavg(IP)) / 100) + 0.1) socket.setdefaulttimeout(timeout) notice("I'm scanning with a timeout of " + str(timeout)) reply("Scanning ports... Please wait a moment !") toreply = "List of minecraft servers found for : " + str(IP) + ":\n" start = 20000 end = 40000 scan = Scanner() scan.open = [] scan.host = IP scan.ports = list(range(start, end)) serversPorts = scan.start() others = [] for port in serversPorts: mcinf = pingmc(IP, port) if mcinf: toreply += "Server found on port " + str(port) + " : " + str(mcinf) + "\n" else: others.append(port) if others: toreply += "Other(s) open ports found, but that don't seems to have a minecraft server on them :" + str(others) if len(serversPorts) == 0: toreply += "No servers found. Check the entered IP address." if len(serversPorts) < 5: return toreply else: return web.paste(strip_all(toreply).encode("latin-1",errors='replace'))
def newegg(text, admin_log, reply): """<item name> - searches newegg.com for <item name>""" # form the search request request = {"Keyword": text, "Sort": "FEATURED"} # newegg thinks it's so damn smart blocking my scraper headers = { 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) ' 'Version/5.1 Mobile/9A334 Safari/7534.48.3', 'Referer': 'http://www.newegg.com/' } # submit the search request try: request = requests.post( 'http://www.ows.newegg.com/Search.egg/Advanced', data=json.dumps(request).encode('utf-8'), headers=headers) except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: return "Unable to find product: {}".format(e) r = request.json() if not request.ok: if r.get("Message"): msg = "{ExceptionMessage}\n{ExceptionType}\n{StackTrace}".format( **r).replace("\r", "") url = web.paste(msg) admin_log("Newegg API Error: {ExceptionType}: {url}".format( url=url, **r)) return "Newegg Error: {Message} (\x02{code}\x02)".format( code=request.status_code, **r) reply("Unknown error occurred.") request.raise_for_status() return # get the first result if r["ProductListItems"]: return format_item(r["ProductListItems"][0]) return "No results found."
def friends(text, chan, conn, db): """Prints a list of the top monster friends in the channel, if 'global' is specified all channels in the database are included.""" if chan in opt_out: return friends = defaultdict(int) chancount = defaultdict(int) out = "" if text.lower() == 'global' or text.lower() == 'average': out = "Monster friend scores across the network: " scores = db.execute(select([table.c.name, table.c.befriend]) \ .where(table.c.network == conn.name) \ .order_by(desc(table.c.befriend))) if scores: for row in scores: if row[1] == 0: continue chancount[row[0]] += 1 friends[row[0]] += row[1] if text.lower() == 'average': for k, v in friends.items(): friends[k] = int(v / chancount[k]) else: return "it appears no one has friended any monsters yet." else: out = "Monster friend scores in {}: ".format(chan) scores = db.execute(select([table.c.name, table.c.befriend]) \ .where(table.c.network == conn.name) \ .where(table.c.chan == chan.lower()) \ .order_by(desc(table.c.befriend))) if scores: for row in scores: if row[1] == 0: continue friends[row[0]] += row[1] else: return "it appears no one has friended any monsters yet." topfriends = sorted(friends.items(), key=operator.itemgetter(1), reverse = True) url = web.paste(json.dumps(topfriends, indent=4)) out += ' • '.join(["{}: {}".format('\x02' + k[:1] + u'\u200b' + k[1:] + '\x02', str(v)) for k, v in topfriends]) out = smart_truncate(out) out += " " + url return out
def list_langs(): """- List the languages/codes that can be used to translate. Translation is powered by Yandex https://translate.yandex.com""" api_key = bot.config.get_api_key("yandex_translate") if not api_key: return "This command requires a Yandex Translate API key" url = api_url + "getLangs" params = {'key': api_key, 'ui': 'en'} data = http.get_json(url, params=params) langs = data['langs'] out = "Language Codes:" out += ",".join("\n{}-{}".format(key, value) for (key, value) in sorted(langs.items())) out += "\n\nTranslation directions:" out += ",".join("\n{}".format(code) for code in data['dirs']) paste = web.paste(out, ext="txt") return "Here is information on what I can translate as well as valid language codes. {}".format( paste)
def list_all_ignores(db, conn, text): """<chan> - List all ignores for <chan>, requires elevated permissions""" rows = db.query(ignores) \ .filter(ignores.conn == conn.name.lower()) \ .filter(ignores.chan == text.lower()) \ .all() ignores = OrderedDict() for row in rows: ignores.setdefault(row.chan, []).append(row.mask) out = "" for chan, masks in ignores.items(): out += "Ignores for {}:\n".format(chan) for mask in masks: out += '- {}\n'.format(mask) out += '\n' return web.paste(out)
def raw_query(text, db, reply, conn): """ <query> - Execute a raw query against the database :type text: str :type db: sqlalchemy.orm.Session :type reply: function :type conn: cloudbot.client.Client """ if not conn.nick.lower().endswith('-dev'): # This command should be disabled in the production bot return "This command may only be used in testing" try: start = datetime.datetime.now() res = db.execute(text) end = datetime.datetime.now() duration = end - start except Exception as e: reply(str(e)) raise else: if res.returns_rows: lines = [ "Results for '{}':".format(text), *("{}".format(tuple(r)) for r in res), "Completed in {:.3f} seconds".format(duration.total_seconds()) ] else: lines = [ "{} rows affected in {:.3f} seconds.".format( res.rowcount, duration.total_seconds()) ] if len(lines) > 5: return web.paste('\n'.join(lines)) else: return lines
def lyrics(text): """<search> - search AZLyrics.com for song lyrics""" if "pastelyrics" in text: dopaste = True text = text.replace("pastelyrics", "").strip() else: dopaste = False soup = http.get_soup(url + text.replace(" ", "+")) if "Try to compose less restrictive search query" in soup.find('div', {'id': 'inn'}).text: return "No results. Check spelling." div = None for i in soup.findAll('div', {'class': 'sen'}): if "/lyrics/" in i.find('a')['href']: div = i break if div: title = div.find('a').text link = div.find('a')['href'] if dopaste: newsoup = http.get_soup(link) try: lyrics = newsoup.find('div', {'style': 'margin-left:10px;margin-right:10px;'}).text.strip() pasteurl = " " + web.paste(lyrics) except Exception as e: pasteurl = " (\x02Unable to paste lyrics\x02 [{}])".format(str(e)) else: pasteurl = "" artist = div.find('b').text.title() lyricsum = div.find('div').text if "\r\n" in lyricsum.strip(): lyricsum = " / ".join(lyricsum.strip().split("\r\n")[0:4]) # truncate, format else: lyricsum = " / ".join(lyricsum.strip().split("\n")[0:4]) # truncate, format return "\x02{}\x02 by \x02{}\x02 {}{} - {}".format(title, artist, web.try_shorten(link), pasteurl, lyricsum[:-3]) else: return "No song results. " + url + text.replace(" ", "+")
def generatehelp(conn, bot): """- Dumps a list of commands with their help text to the docs directory formatted using markdown.""" message = "{} Command list\n".format(conn.nick) message += "------\n" for plugin in sorted(set(bot.plugin_manager.commands.values()), key=attrgetter("name")): # use set to remove duplicate commands (from multiple aliases), and sorted to sort by name command = plugin.name aliases = "" doc = bot.plugin_manager.commands[command].doc permission = "" for perm in plugin.permissions: permission += perm + ", " permission = permission[:-2] for alias in plugin.aliases: if alias == command: pass else: aliases += alias + ", " aliases = aliases[:-2] if doc: doc = doc.replace("<", "<").replace(">", ">") \ .replace("[", "<").replace("]", ">") if aliases: message += "**{} ({}):** {}\n\n".format(command, aliases, doc) else: # No aliases so just print the commands message += "**{}**: {}\n\n".format(command, doc) else: message += "**{}**: Command has no documentation.\n\n".format( command) if permission: message = message[:-2] message += " ( *Permission required:* {})\n\n".format(permission) # toss the markdown text into a paste return web.paste(message)
def list_all_ignores(db, conn, text): """<chan> - List all ignores for <chan>, requires elevated permissions""" whereclause = table.c.connection == conn.name.lower() if text: whereclause = and_(whereclause, table.c.channel == text.lower()) rows = db.execute(select([table.c.channel, table.c.mask], whereclause)).fetchall() ignores = OrderedDict() for row in rows: ignores.setdefault(row['channel'], []).append(row['mask']) out = "" for chan, masks in ignores.items(): out += "Ignores for {}:\n".format(chan) for mask in masks: out += '- {}\n'.format(mask) out += '\n' return web.paste(out)
def newegg(text, admin_log, reply): """<item name> - searches newegg.com for <item name>""" # form the search request request = {"Keyword": text, "Sort": "FEATURED"} # submit the search request try: request = requests.post(API_SEARCH, data=json.dumps(request).encode('utf-8'), headers=HEADERS) except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: return "Unable to find product: {}".format(e) r = request.json() if not request.ok: if r.get("Message"): msg = "{ExceptionMessage}\n{ExceptionType}\n{StackTrace}".format( **r).replace("\r", "") url = web.paste(msg) admin_log("Newegg API Error: {ExceptionType}: {url}".format( url=url, **r)) return "Newegg Error: {Message} (\x02{code}\x02)".format( code=request.status_code, **r) else: reply("Unknown error occurred.") request.raise_for_status() return # get the first result if r["ProductListItems"]: return format_item("com", r["ProductListItems"][0]) else: return "No results found."
def llistfaq(reply, event): WorkingWithFiles.checkExistsFile("data/local_faq/" + event.chan) file = open("data/local_faq/" + event.chan, 'r').read().encode('UTF-8') lien = web.paste(file) reply(str(lien))
def paste_facts(facts, raise_on_no_paste=False): headers = ("Command", "Output") data = [(FACTOID_CHAR + fact[0], fact[1]) for fact in sorted(facts.items())] tbl = gen_markdown_table(headers, data).encode('UTF-8') return web.paste(tbl, 'md', 'hastebin', raise_on_no_paste=raise_on_no_paste)
def listfaq(reply): file = open('data/faq.json', 'r').read().encode('UTF-8') lien = web.paste(file) reply(str(lien))