From 132b88233c038f87646e729b03b9f498a4112452 Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 15:05:10 -0400 Subject: [PATCH 1/7] Updated tapir bot.py with cogs functionality Changes almost everything --- tapir bot.py | 178 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 110 insertions(+), 68 deletions(-) diff --git a/tapir bot.py b/tapir bot.py index faf2ed0..f8f15dc 100644 --- a/tapir bot.py +++ b/tapir bot.py @@ -1,71 +1,113 @@ -#https://discordapp.com/oauth2/authorize?&client_id=173642301921296385&scope=bot&permissions=0 -#random tapir bot - - -import random #imports the random module -import discord #imports the discord api module thing -import asyncio #imports asyncio -import tapir_module - -client = discord.Client() #easier coding! - -tapir = tapir_module.tapirbot() #initializes the tapir - -@client.event -async def on_ready(): #same here, maybe when bot is ready it does the thing - """the client starting up, once up, what it doess""" - await client.change_status(game=discord.Game(name=tapir.current_game)) #puts a help command in the game played - await tapir.startup(client) - -@client.event -async def on_message(message): #when someone sends a message - """the stuff that happens when a message is sent""" - channel = message.channel #defines the channel the messages is sent to as a variable - raw_message = message #the message content is ssaved - message = message.content.lower() #the message is put into a lower case format - if len(message) >= 1: #must have atleast one character in the message - message = message.split(' ') #message is made into a list split at every ' ' - if message[0].startswith('!'): #prefix is defined as '!' - try: - if message[0] in tapir.commands: #if not tapir checks if command in the the command dictionary - await tapir.print_message(message[0], raw_message) #gets the console stuff - await client.send_message(raw_message.channel, tapir.commands[message[0]]) #says the commands text - elif message[0] == '!tapir' or message[0] == '!taper': #the tapir command! - await tapir.print_message(message[0], raw_message) #gets the console stuff - await tapir.tapir(raw_message, client) #gets the tapir image - elif message[0] == '!add_tapir' and raw_message.author.id == '149281074437029890': #add tapirs to the text if you are me :) - new_tapir = raw_message.content.split(' ')[1] - tapir.tapirs_text.write(new_tapir + "\n") #adds the link and a line ender thing (can't remember name) - tapir.tapirs.append(new_tapir) #also puts the link in the list for immediate usage - tapir.images = len(tapir.tapirs) #allows to use instantly - await tapir.print_message(message[0], raw_message) #prints on console - await client.send_message(raw_message.channel, "Got it! :thumbsup:") #confirms the tapir - elif message[0] == '!reply' and raw_message.author.id == '149281074437029890': #can communicate through tapir-bot - await tapir.send_message(raw_message, client) - elif message[0] == '!close' and raw_message.author.id == '149281074437029890': #if you're me you can close tapir-bot - tapir.tapirs_text.close() #closes the tapir.txt - await client.logout() #logs tapir-bot out - elif message[0] == '!attack' and message[1] == 'define' and raw_message.channel.id != '82210263440306176': #to define a attacking pair - await tapir.print_message(message[1], raw_message) #prints to the console - await tapir.define(message[2:5:2], raw_message, client) #calls the define function - elif message[0] == '!attack' and message[1] == 'reset' and raw_message.channel.id != '82210263440306176': #the reset function of attack - await tapir.print_message(message[1], raw_message) - await tapir.reset(raw_message, client) - elif message[0] == '!attack' and raw_message.channel.id != '82210263440306176': #attack command! It doesn't go to /r/starcitizen's general channel - try: #caususe index errors happen - await tapir.attack(message[1:4:2], raw_message, client) #does the attacking - await tapir.print_message(message[0], raw_message) #gets the console stuff - except IndexError: #if someone is dumb and forgets the character to play as - await client.send_message(raw_message.channel, "Whoops, you forgot did something wrong!") - await tapir.print_message("Attack_list_error", raw_message) - except: - pass - elif raw_message.channel.is_private and not raw_message.author.id == '173648334479687681': #if it has no command but is PMed to tapir-bot it will tell me - print(raw_message.author.name + ' private message') - await tapir.private_message_recieved(raw_message, client) +from discord.ext import commands +import discord +from cogs.utils import checks +import datetime, re +import json, asyncio +import copy +import logging +import traceback +import sys +from collections import Counter + +description = """ +I am a bot written by treefroog to provide tapirs +""" + +initial_extensions = [ + 'cogs.admin', + 'cogs.meta', + 'cogs.mod' + ] + +discord_logger = logging.getLogger('discord') +discord_logger.setLevel(logging.CRITICAL) +log = logging.getLogger() +log.setLevel(logging.INFO) +handler = logging.FileHandler(filename='tapir-bot.log', encoding='utf-8', mode='w') +log.addHandler(handler) + +help_attrs = dict(hidden=True) + +bot = commands.Bot(command_prefix=['!'], description=description, pm_help=None, help_attrs=help_attrs) + +@bot.event +async def on_command_error(error, ctx): + if isinstance(error, commands.NoPrivateMessage): + await bot.send_message(ctx.message.author, 'This command cannot be used in private messages.') + elif isinstance(error, commands.DisabledCommand): + await bot.send_message(ctx.message.author, 'Sorry. This command is disabled and cannot be used.') + elif isinstance(error, commands.CommandInvokeError): + print('In {0.command.qualified_name}:'.format(ctx), file=sys.stderr) + traceback.print_tb(error.original.__traceback__) + print('{0.__class__.__name__}: {0}'.format(error.original), file=sys.stderr) + + +@bot.event +async def on_ready(): + print('Logged in as:') + print('Username: ' + bot.user.name) + print('ID: ' + bot.user.id) + for s in bot.servers: + print(s.name) + print('----------') + if not hasattr(bot, 'uptime'): + bot.uptime = datetime.datetime.utcnow() + +@bot.event +async def on_message(message): + if message.author == bot.user: + return + + if message.author.bot: + return + + mod = bot.get_cog('Mod') + + if mod is not None and not checks.is_owner_check(message): + # check if the user is bot banned + if message.author.id in mod.config.get('plonks', []): + return + + # check if the channel is ignored + # but first, resolve their permissions + + perms = message.channel.permissions_for(message.author) + bypass_ignore = perms.manage_roles + + # if we don't have manage roles then we should + # check if it's the owner of the bot or they have Bot Admin role. + + if not bypass_ignore: + if not message.channel.is_private: + bypass_ignore = discord.utils.get(message.author.roles, name='Bot Admin') is not None + + # now we can finally realise if we can actually bypass the ignore. + + if not bypass_ignore: + if message.channel.id in mod.config.get('ignored', []): + return + + await bot.process_commands(message) + +def load_credentials(): + with open('credentials.json') as f: + return json.load(f) - +if __name__ == '__main__': + if any('debug' in arg.lower() for arg in sys.argv): + bot.command_prefix = '!' + credentials = load_credentials() + bot.client_id = credentials['client_id'] + bot.commands_used = Counter() + for extension in initial_extensions: + try: + bot.load_extension(extension) + except Exception as e: + print('Failed to load extension {}\n{}: {}'.format(extension, type(e).__name__, e)) - -client.run('bot_token') #bot token \ No newline at end of file + bot.run(credentials['token']) + handlers = log.handlers[:] + for hdlr in handlers: + hdlr.close() + log.removeHandler(hdlr) From 4d13e5700849f0d0ee77e9b295f81d2b2b01e592 Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 15:05:32 -0400 Subject: [PATCH 2/7] Delete tapir_module.py Don't need this with cogs --- tapir_module.py | 107 ------------------------------------------------ 1 file changed, 107 deletions(-) delete mode 100644 tapir_module.py diff --git a/tapir_module.py b/tapir_module.py deleted file mode 100644 index 84ec60c..0000000 --- a/tapir_module.py +++ /dev/null @@ -1,107 +0,0 @@ -#tapir-bot other file - -import asyncio -import discord -import random - -class tapirbot(): - """the tapirbot master""" - def __init__(self): - """all the startup junk""" - self.tapirs_text = open('tapirs.txt', 'r+') #tapir .txt file is opened - self.tapirs = [x.strip() for x in self.tapirs_text.readlines()] #makes a list out of the file and removes the '\n' - - self.images = len(self.tapirs) #sets the length to the length of the list - - self.current_game = "say \"!?\" for help" #the current game message - - self.pairs = [ - ['georgie', 'pennywise'] - ] - - self.pair_health = [ - [100, 100] - ] - - self.commands = { #command dictioinary - '!?' : 'Hello! I am a bot made by <@149281074437029890> . \n say `!tapir` to get a random tapir image! \n say `!carrack` for a Carrack picture. \n say `!azwe` for @Azwethinkweiz\'s beautiful mocap animation. \n say `!ben` to get Ben\'s beautiful dancing. \n say `!2.4` to get an update on the new 2.4 update. \n say `!scam` to know the truth of Star Citizen. \n say `!attack ` to play the attacking minigame. say `!attack help` for more information. \n say `!source` for my Github!', - '!carrack' : 'Carrack pls http://i.imgur.com/BA3F1OI.png', - '!azwe': '<@118907180761088006> https://giphy.com/gifs/IEceC9q1MgWrK', - '!ben' : 'http://i.imgur.com/OLKOQ6H.gif', - '!2.4' : 'It\'s not just a meme! http://i.imgur.com/umBUjqW.gif', - '!scam' : 'Star Citizen is a scam, confirmed by Chris Roberts himself: http://i.imgur.com/UK3D1c0.gifv', - '!source' : 'My Github is here: https://github.com/treefroog/tapir-bot' -} - - async def startup(self, client): #when the client starts it prints all this junk - """prints the startup stuff like the name of the bot, and the name of the server the bot is in""" - print('Logged in as') #I know this one - print(client.user.name) #prints the bots user name - print("\nServers:") #puts "Servers" and a new line - for s in client.servers: #lists the servers. Broken for all except TAPIR BOT server. Sometimes works. IDK why - print(s.name) - print('----------------') #prints '------' at end of startup squence - - async def print_message(self, message, raw_message): #prints the name of author and stuff - """prints the name of author, commaand used, channel, and server that it was called in""" - print(message, end=' ') #prints command on console - print(raw_message.author, end=' @') #prints message author - print(raw_message.server, end=':') #prints in console the server that the message was in with a ':' at the end - print(raw_message.channel) #prints the server's channel - - async def private_message_recieved(self, raw_message, client): #when tapir-bot recieves a private message - """sends me a private message of the channel ID and the author name and content""" - await client.send_message(client.get_channel('173957638302728192'), '{} : {} \n {}'.format(raw_message.channel.id, raw_message.author.name, raw_message.content)) - - async def send_message(self, raw_message, client): - """I send a message, through tapir-bot""" - message = raw_message.content.split(' ') #makes the message a list of the words - receiver = message[1] #the channel is the ID I send - receiver = client.get_channel(receiver) #it makes that into a channel class - del message[0:2] #in message it deletes thee first two indexes - message = ' '.join(message) #joins the list back together with a space inbeetween the indexes - print(str(receiver) + ' : ' + message) #on consol it prints the channel and the message - await client.send_message(receiver, message) #send the message - - - async def tapir(self, message, client): #when someone calls the !tapir command - """the tapir command function""" - taper = self.tapirs[random.randrange(self.images)] #generates the tapir - await client.send_message(message.channel, taper) #sends the tapir - - async def define(self, pair, raw_message, client): - """will define a new pair for attack""" - if pair not in self.pairs and pair[::-1] not in self.pairs: #if it's not defined - self.pairs.append(pair) #puts the pair in - self.pair_health.append([100, 100]) #appends the health to the health list - await client.send_message(raw_message.channel, '{} vs. {} is ready!'.format(pair[0], pair[1])) #confirms they are added - else: #if it's already defined - await client.send_message(raw_message.channel, '{} vs. {} is already defined.'.format(pair[0], pair[1])) #says they are already defined - - async def reset(self, raw_message, client): - """resets all of the healths to 100""" - for pair in range(len(self.pair_health)): #for the pair in the health list - for character in range(len(self.pair_health[pair])): #for every character in the pair - self.pair_health[pair][character] = 100 #their health is 100 - await client.send_message(raw_message.channel, 'All healths reset!') - - async def attack(self, pair, raw_message, client): - """attack command, with unlimited pairs""" - if pair in self.pairs or pair[::-1] in self.pairs: #if they are in the list - attacker = pair[0] #makes sure to define which is the attacker - defender = pair[1] #and the defender - if pair not in self.pairs: #if the base isn't in, it reverse the two - pair = pair[::-1] - pair_index = self.pairs.index(pair) #finds the index of the pair in the pairs list - attacker_index = self.pairs[pair_index].index(attacker) #finds the index of the attacker - defender_index = self.pairs[pair_index].index(defender) #and the defender - if self.pair_health[pair_index][attacker_index] > 0: #if the attacker is still alive - damage = random.randrange(10, 21) #he damages the defender - self.pair_health[pair_index][defender_index] -= damage #applies the damage - if self.pair_health[pair_index][defender_index] > 0: #if the defender is still alive - await client.send_message(raw_message.channel, '{} did {} damage to {}, who has {} health left'.format(attacker, damage, defender, self.pair_health[pair_index][defender_index])) #says how much health is left of defender and such - else: #if the defender has 0 or less health after being damaged - await client.send_message(raw_message.channel, '{} is dead!'.format(defender)) #if the defender dies it says so - else: #if the attacker is dead - await client.send_message(raw_message.channel, '{} is dead, they can\'t attack!'.format(attacker)) #says so - \ No newline at end of file From ce19181826f56ccf7e26d0171962eba8cb02d0cb Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 15:05:49 -0400 Subject: [PATCH 3/7] Delete tapirs.txt Don't need this with cogs --- tapirs.txt | 133 ----------------------------------------------------- 1 file changed, 133 deletions(-) delete mode 100644 tapirs.txt diff --git a/tapirs.txt b/tapirs.txt deleted file mode 100644 index 11cc5e2..0000000 --- a/tapirs.txt +++ /dev/null @@ -1,133 +0,0 @@ -http://i.imgur.com/e18ZHri.png -http://i.imgur.com/VJDf9s1.png -http://i.imgur.com/dRAiEe4.png -http://i.imgur.com/wdova3J.png -http://i.imgur.com/tJjx4qK.png -http://i.imgur.com/qeN3TjM.png -http://i.imgur.com/tHPhFMa.gif -http://i.imgur.com/WKQiNFw.jpg -http://i.imgur.com/x4j0d90.jpg -http://i.imgur.com/Rla6CxQ.jpg -http://i.imgur.com/TvbXgVi.jpg -http://i.imgur.com/14P5ikM.jpg -http://i.imgur.com/ktviJuC.png -http://i.imgur.com/6994eHI.png -http://i.imgur.com/5NwpK4M.jpg -http://i.imgur.com/tpcRmnE.jpg -http://i.imgur.com/Q3fk7iI.png -http://i.imgur.com/OXLj8ev.png -http://i.imgur.com/OYTzAWh.jpg -http://i.imgur.com/UkBNbfh.png -http://i.imgur.com/oC8wpfE.png -http://i.imgur.com/ysuEpzp.png -http://i.imgur.com/H2LU6Yv.png -http://i.imgur.com/fnPNxxz.png -http://i.imgur.com/a6ULF53.png -http://i.imgur.com/PwodKBZ.png -http://i.imgur.com/8kzzOoV.png -http://i.imgur.com/Qurbk2d.png -http://i.imgur.com/EV4Xr1D.png -http://i.imgur.com/g2gxNsq.jpg -http://i.imgur.com/3TTRki4.jpg -http://i.imgur.com/9MTpv1c.png -http://i.imgur.com/7zVbBDQ.jpg -http://i.imgur.com/xncjSd7.png -http://i.imgur.com/4SiThqS.png -http://i.imgur.com/A0kOELj.png -http://i.imgur.com/6BgR8WB.png -http://i.imgur.com/96Ue3sg.png -http://i.imgur.com/oFrncNz.png -http://i.imgur.com/q9KKE6D.png -http://i.imgur.com/FhXFun1.png -http://i.imgur.com/mxZtX8j.png -http://i.imgur.com/BKUUzmO.png -http://i.imgur.com/S1vKjhl.jpg -http://i.imgur.com/MWuXrUO.png -http://i.imgur.com/uzYhQ9W.png -http://i.imgur.com/HM7oIKc.png -http://i.imgur.com/ONGCZhO.gif -http://i.imgur.com/MwgplL8.png -http://i.imgur.com/R8y3v49.jpg -http://i.imgur.com/QSC0cSu.png -http://i.imgur.com/11ZBtG7.png -http://i.imgur.com/XfyT4H5.gif -http://i.imgur.com/oLC9AyL.jpg -http://i.imgur.com/0KVeMLf.jpg -http://i.imgur.com/MPBZafq.png -http://i.imgur.com/7g7LHjf.png -http://i.imgur.com/oxgAUQA.png -http://i.imgur.com/2W42kNe.jpg -http://i.imgur.com/KmuiOzA.jpg -http://i.imgur.com/lGofpCK.jpg -http://i.imgur.com/pllUFWw.jpg -http://i.imgur.com/kr2w5TZ.png -http://i.imgur.com/1nmhYLT.png -http://i.imgur.com/NfWZFze.png -http://i.imgur.com/l91ZWw1.png -http://i.imgur.com/ss1jKr8.png -http://i.imgur.com/EiYlaVb.png -http://i.imgur.com/f3jl9Qi.png -http://i.imgur.com/1jOb6Hb.png -http://i.imgur.com/dyfC203.png -http://i.imgur.com/MW4JNJt.png -http://i.imgur.com/i4lt0Cg.png -http://i.imgur.com/38qGdwX.png -http://i.imgur.com/XebMxP5.png -http://i.imgur.com/qZx3d3D.png -http://i.imgur.com/vCy8rFr.png -http://i.imgur.com/Mlywcnm.png -http://i.imgur.com/Dmc2uM8.jpg -http://i.imgur.com/9qKB1mk.png -http://i.imgur.com/SkwJ8KZ.jpg -http://i.imgur.com/9r35TCm.png -http://i.imgur.com/WkzM3hh.png -http://i.imgur.com/VGXNPtU.png -http://i.imgur.com/fQegjXU.png -http://i.imgur.com/jaZmvMs.jpg -http://i.imgur.com/9j63Lov.png -http://i.imgur.com/9kdYMx5.png -http://i.imgur.com/R21a14U.png -http://i.imgur.com/JJobslO.png -http://i.imgur.com/KNPWux1.gif -http://i.imgur.com/xxIdm31.gif -http://i.imgur.com/q3oAWFt.png -http://i.imgur.com/CYWQnuP.png -http://i.imgur.com/7QeekYS.png -http://i.imgur.com/EoUQCCX.png -http://i.imgur.com/KYfjHot.png -http://i.imgur.com/JuXH2bj.png -http://i.imgur.com/A7SxRbS.png -http://i.imgur.com/NDPnnJt.png -http://i.imgur.com/5auCaYR.jpg -http://i.imgur.com/WtepfQT.jpg -http://i.imgur.com/yyNs8CK.jpg -http://i.imgur.com/TPkprQp.jpg -http://i.imgur.com/QKkwMb4.jpg -http://i.imgur.com/SpTkfSe.png -http://i.imgur.com/ARkCIh3.png -http://i.imgur.com/lwgZz3y.jpg -http://i.imgur.com/WWjdn1y.png -http://i.imgur.com/YY0vemL.png -http://i.imgur.com/alDQH24.png -http://i.imgur.com/YMlJiNe.png -http://i.imgur.com/7C9zku8.png -http://i.imgur.com/iPSoLjm.png -http://i.imgur.com/FCP1Tzq.png -http://i.imgur.com/vE2XIEy.png -http://i.imgur.com/aEcshrV.gif -http://i.imgur.com/PgYNH9a.png -http://i.imgur.com/TOvEB8a.png -http://i.imgur.com/vZ4sYdu.png -http://i.imgur.com/WZE99Mw.png -http://i.imgur.com/cF5nXWa.jpg -http://i.imgur.com/NGelpAd.png -http://i.imgur.com/G3MOhCm.png -http://i.imgur.com/wmJ7ICc.jpg -http://i.imgur.com/6jvO9Yr.png -http://i.imgur.com/F1lqJ87.png -http://i.imgur.com/aFfDMyX.png -http://i.imgur.com/tgPoQ9S.jpg -http://i.imgur.com/n2BjyFA.png -http://i.imgur.com/Kjza1Q5.png -http://i.imgur.com/wtepfqt.jpg -http://i.imgur.com/5asdull.png From 8820b3ae279607817e28ebd77967e02da73ed974 Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 15:07:27 -0400 Subject: [PATCH 4/7] Create .gitignore To not sync confidential stuff --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..189fdf6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/* +*.json +*.pyc From 80c46a52fafb7a8a5bea080aa9dc84c7c6bf0553 Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 15:17:29 -0400 Subject: [PATCH 5/7] Cogs being added The largest change yet to tapir-bot. Adds the awesome discord.py commands extension. Makes the front end super cool and the backend super easy. Also makes it so that I can have one version instead of a github version and a real version since I can make it not sync certain files. --- cogs/admin.py | 78 ++++++++++++++++++++++++++++++ cogs/meta.py | 43 +++++++++++++++++ cogs/mod.py | 107 +++++++++++++++++++++++++++++++++++++++++ cogs/ships.py | 20 ++++++++ cogs/tapir.py | 33 +++++++++++++ cogs/utils/__init__.py | 0 cogs/utils/checks.py | 67 ++++++++++++++++++++++++++ cogs/utils/config.py | 55 +++++++++++++++++++++ cogs/utils/formats.py | 38 +++++++++++++++ mod.json | 1 + tapir bot.py | 2 +- tapirs.json | 1 + 12 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 cogs/admin.py create mode 100644 cogs/meta.py create mode 100644 cogs/mod.py create mode 100644 cogs/ships.py create mode 100644 cogs/tapir.py create mode 100644 cogs/utils/__init__.py create mode 100644 cogs/utils/checks.py create mode 100644 cogs/utils/config.py create mode 100644 cogs/utils/formats.py create mode 100644 mod.json create mode 100644 tapirs.json diff --git a/cogs/admin.py b/cogs/admin.py new file mode 100644 index 0000000..059ab2e --- /dev/null +++ b/cogs/admin.py @@ -0,0 +1,78 @@ +from discord.ext import commands +from .utils import checks +import discord +import inspect +import asyncio + +class Admin: + """Admin-only commands that make the bot dynamic.""" + + def __init__(self, bot): + self.bot = bot + + @commands.command(hidden=True) + @checks.is_owner() + async def load(self, *, module : str): + """Loads a module.""" + try: + self.bot.load_extension(module) + except Exception as e: + await self.bot.say('\N{PISTOL}') + await self.bot.say('{}: {}'.format(type(e).__name__, e)) + else: + await self.bot.say('\N{OK HAND SIGN}') + + @commands.command(hidden=True) + @checks.is_owner() + async def unload(self, *, module : str): + """Unloads a module.""" + try: + self.bot.unload_extension(module) + except Exception as e: + await self.bot.say('\N{PISTOL}') + await self.bot.say('{}: {}'.format(type(e).__name__, e)) + else: + await self.bot.say('\N{OK HAND SIGN}') + + @commands.command(name='reload', hidden=True) + @checks.is_owner() + async def _reload(self, *, module : str): + """Reloads a module.""" + try: + self.bot.unload_extension(module) + self.bot.load_extension(module) + except Exception as e: + await self.bot.say('\N{PISTOL}') + await self.bot.say('{}: {}'.format(type(e).__name__, e)) + else: + await self.bot.say('\N{OK HAND SIGN}') + + @commands.command(pass_context=True, hidden=True) + @checks.is_owner() + async def debug(self, ctx, *, code : str): + """Evaluates code.""" + code = code.strip('` ') + python = '```py\n{}\n```' + result = None + + env = { + 'bot': self.bot, + 'ctx': ctx, + 'message': ctx.message, + 'server': ctx.message.server, + 'channel': ctx.message.channel, + 'author': ctx.message.author + } + + try: + result = eval(code, env) + if inspect.isawaitable(result): + result = await result + except Exception as e: + await self.bot.say(python.format(type(e).__name__ + ': ' + str(e))) + return + + await self.bot.say(python.format(result)) + +def setup(bot): + bot.add_cog(Admin(bot)) \ No newline at end of file diff --git a/cogs/meta.py b/cogs/meta.py new file mode 100644 index 0000000..6fe4559 --- /dev/null +++ b/cogs/meta.py @@ -0,0 +1,43 @@ +from discord.ext import commands +from .utils import checks, formats +import discord +from collections import OrderedDict, deque, Counter +import os, datetime +import re, asyncio +import copy + + + +class Meta: + """Commands for utilities related to Discord or the Bot itself.""" + + def __init__(self, bot): + self.bot = bot + + @commands.command(hidden=True) + async def hello(self): + """Displays my hello message.""" + await self.bot.say('Hello! I\'m a bot made by <@149281074437029890>') + + @commands.command(rest_is_raw=True, hidden=True, aliases=['say']) + @checks.is_owner() + async def echo(self, *, content): + """says stuff that I tell it to""" + await self.bot.say(content) + + @commands.command(name='quit', hidden=True) + @checks.is_owner() + async def _quit(self): + """quits tapir-bot""" + await self.bot.logout() + + @commands.command(hidden=True) + @checks.is_owner() + async def commandstats(self): + """gives me command stats""" + msg = 'Since startup, {} commands have been used.\n{}' + counter = self.bot.commands_used + await self.bot.say(msg.format(sum(counter.values()), counter)) + +def setup(bot): + bot.add_cog(Meta(bot)) \ No newline at end of file diff --git a/cogs/mod.py b/cogs/mod.py new file mode 100644 index 0000000..3f83646 --- /dev/null +++ b/cogs/mod.py @@ -0,0 +1,107 @@ +from discord.ext import commands +from .utils import config, checks +from collections import Counter +import re +import discord +import asyncio + +class Mod: + """Moderation related commands.""" + + def __init__(self, bot): + self.bot = bot + self.config = config.Config('mod.json', loop=bot.loop) + + def bot_user(self, message): + return message.server.me if message.channel.is_private else self.bot.user + + @commands.group(pass_context=True, no_pm=True) + @checks.admin_or_permissions(manage_channels=True) + async def ignore(self, ctx): + """Handles the bot's ignore lists. + To use these commands, you must have the Bot Admin role or have + Manage Channels permissions. These commands are not allowed to be used + in a private message context. + Users with Manage Roles or Bot Admin role can still invoke the bot + in ignored channels. + """ + if ctx.invoked_subcommand is None: + await self.bot.say('Invalid subcommand passed: {0.subcommand_passed}'.format(ctx)) + + @ignore.command(name='list', pass_context=True) + async def ignore_list(self, ctx): + """Tells you what channels are currently ignored in this server.""" + + ignored = self.config.get('ignored', []) + channel_ids = set(c.id for c in ctx.message.server.channels) + result = [] + for channel in ignored: + if channel in channel_ids: + result.append('<#{}>'.format(channel)) + + if result: + await self.bot.say('The following channels are ignored:\n\n{}'.format(', '.join(result))) + else: + await self.bot.say('I am not ignoring any channels here.') + + @ignore.command(name='channel', pass_context=True) + async def channel_cmd(self, ctx, *, channel : discord.Channel = None): + """Ignores a specific channel from being processed. + If no channel is specified, the current channel is ignored. + If a channel is ignored then the bot does not process commands in that + channel until it is unignored. + """ + + if channel is None: + channel = ctx.message.channel + + ignored = self.config.get('ignored', []) + if channel.id in ignored: + await self.bot.say('That channel is already ignored.') + return + + ignored.append(channel.id) + await self.config.put('ignored', ignored) + await self.bot.say('\U0001f44c') + + @ignore.command(name='all', pass_context=True) + @checks.admin_or_permissions(manage_server=True) + async def _all(self, ctx): + """Ignores every channel in the server from being processed. + This works by adding every channel that the server currently has into + the ignore list. If more channels are added then they will have to be + ignored by using the ignore command. + To use this command you must have Manage Server permissions along with + Manage Channels permissions. You could also have the Bot Admin role. + """ + + ignored = self.config.get('ignored', []) + channels = ctx.message.server.channels + ignored.extend(c.id for c in channels if c.type == discord.ChannelType.text) + await self.config.put('ignored', list(set(ignored))) # make unique + await self.bot.say('\U0001f44c') + + @commands.command(pass_context=True, no_pm=True) + @checks.admin_or_permissions(manage_channels=True) + async def unignore(self, ctx, *, channel : discord.Channel = None): + """Unignores a specific channel from being processed. + If no channel is specified, it unignores the current channel. + To use this command you must have the Manage Channels permission or have the + Bot Admin role. + """ + + if channel is None: + channel = ctx.message.channel + + # a set is the proper data type for the ignore list + # however, JSON only supports arrays and objects not sets. + ignored = self.config.get('ignored', []) + try: + ignored.remove(channel.id) + except ValueError: + await self.bot.say('Channel was not ignored in the first place.') + else: + await self.bot.say('\U0001f44c') + +def setup(bot): + bot.add_cog(Mod(bot)) \ No newline at end of file diff --git a/cogs/ships.py b/cogs/ships.py new file mode 100644 index 0000000..0d90eb7 --- /dev/null +++ b/cogs/ships.py @@ -0,0 +1,20 @@ +from discord.ext import commands +from .utils import checks +import discord +import asyncio + +class Ships: + """all of the Star Citizen ship commands""" + + def __init__(self, bot): + self.bot = bot + + @commands.group(pass_context=True) + async def ship(self, ctx): + """Posts a link to an album of the specified ship""" + if ctx.invoked_subcommand is None: + await self.bot.say('Invalid ship: {0.subcommand_passed}'.format(ctx)) + + @ship.command(pass_context=True, hidden=True) + async def carrack(self): + await self.bot.say('Carrack pls http://i.imgur.com/BA3F1OI.png') \ No newline at end of file diff --git a/cogs/tapir.py b/cogs/tapir.py new file mode 100644 index 0000000..1555f1e --- /dev/null +++ b/cogs/tapir.py @@ -0,0 +1,33 @@ +from discord.ext import commands +from .utils import config, checks +import random +import discord +import asyncio + +class Tapir: + """the tapir command(s)""" + + def __init__(self, bot): + self.bot = bot + + self.config = config.Config('tapirs.json', loop=bot.loop) + + @commands.command() + async def tapir(self): + """The wonderful tapir command that outputs a random tapir""" + tapir_file = config.Config('tapirs.json', loop=bot.loop) + tapirs = tapir_file.get('tapirs') + tapir = tapirs[random.randrange(len(tapirs))] + await self.bot.say(tapir) + + @commands.command(hidden=True) + @checks.is_owner() + async def save_tapir(self, *, tapir): + """allows the saving of a tapirs""" + tapir_file = config.Config('tapirs.json', loop=bot.loop) + tapirs = tapir_file.get('tapirs') + tapirs.append(tapir) + tapir_file.put(tapirs) + +def setup(bot): + bot.add_cog(Tapir(bot)) \ No newline at end of file diff --git a/cogs/utils/__init__.py b/cogs/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py new file mode 100644 index 0000000..61e646d --- /dev/null +++ b/cogs/utils/checks.py @@ -0,0 +1,67 @@ +from discord.ext import commands +import discord.utils + +def is_owner_check(message): + """"is it me?""" + return message.author.id == '149281074437029890' + +def is_owner(): + """is me but diffent""" + return commands.check(lambda ctx: is_owner_check(ctx.message)) + +""" +There is now a permissions system! +if you don't meet a permission to do a command, nothing really happens +but if you are the owner or a so called bot mod you can do stuff +if you are the owner (treefroog) you can do any command +'it just works' +-todd howard +-micheal scott +""" + +def check_permissions(ctx, perms): + """does some permission checking. I can do anything""" + msg = ctx.message + if is_owner_check(msg): + return True + + ch = msg.channel + author = msg.author + resolved = ch.permissions_for(author) + return all(getattr(resolved, name, None) == value for name, value in perms.items()) + +def role_or_permissions(ctx, check, **perms): + """checks roles or permissions, since rolees can do some stuff""" + if check_permissions(ctx, perms): + return True + + ch = ctx.message.channel + author = ctx.message.author + if ch.is_private: + return False # can't have roles in PMs + + role = discord.utils.find(check, author.roles) + return role is not None + +def mod_or_permissions(**perms): + """checks if mod, or permissions to do stuff""" + def predicate(ctx): + return role_or_permissions(ctx, lambda r: r.name in ('Bot Mod', 'Bot Admin'), **perms) + + return commands.check(predicate) + +def admin_or_permissions(**perms): + """checks if admin, or if permission allows to do stuff""" + def predicate(ctx): + return role_or_permissions(ctx, lambda r: r.name == 'Bot Admin', **perms) + + return commands.check(predicate) + +def is_in_servers(*server_ids): + """if is in server""" + def predicate(ctx): + server = ctx.message.server + if server is None: + return False + return server.id in server_ids + return commands.check(predicate) \ No newline at end of file diff --git a/cogs/utils/config.py b/cogs/utils/config.py new file mode 100644 index 0000000..d8a71fc --- /dev/null +++ b/cogs/utils/config.py @@ -0,0 +1,55 @@ +import json +import asyncio + +class Config: + """The "database" object. Internally based on ``json``.""" + + def __init__(self, name, **options): + self.name = name + self.object_hook = options.pop('object_hook', None) + self.encoder = options.pop('encoder', None) + self.loop = options.pop('loop', asyncio.get_event_loop()) + if options.pop('load_later', False): + self.loop.create_task(self.load()) + else: + self.load_from_file() + + def load_from_file(self): + try: + with open(self.name, 'r') as f: + self._db = json.load(f, object_hook=self.object_hook) + except FileNotFoundError: + self._db = {} + + async def load(self): + await self.loop.run_in_executor(None, self.load_from_file) + + def _dump(self): + with open(self.name, 'w') as f: + json.dump(self._db, f, ensure_ascii=True, cls=self.encoder) + + async def save(self): + await self.loop.run_in_executor(None, self._dump) + + def get(self, key, *args): + """Retrieves a config entry.""" + return self._db.get(key, *args) + + async def put(self, key, value, *args): + """Edits a config entry.""" + self._db[key] = value + await self.save() + + async def remove(self, key): + """Removes a config entry.""" + del self._db[key] + await self.save() + + def __contains__(self, item): + return self._db.__contains__(item) + + def __len__(self): + return self._db.__len__() + + def all(self): + return self._db \ No newline at end of file diff --git a/cogs/utils/formats.py b/cogs/utils/formats.py new file mode 100644 index 0000000..8521f80 --- /dev/null +++ b/cogs/utils/formats.py @@ -0,0 +1,38 @@ +#formats messages + +async def entry_to_code(bot, entries): + """formats input into discord code format""" + width = max(map(lambda t: len(t[0]), entries)) + output = ['```'] + fmt = '{0:<{width}}: {1}' + for name, entry in entries: + output.append(fmt.format(name, entry, width=width)) + output.append('```') + await bot.say('\n'.join(output)) + +async def indented_entry_to_code(bot, entries): + """formats input into discord code format with indents""" + width = max(map(lambda t: len(t[0]), entries)) + output = ['```'] + fmt = '\u200b{0:>{width}}: {1}' + for name, entry in entries: + output.append(fmt.format(name, entry, width=width)) + output.append('```') + await bot.say('\n'.join(output)) + +async def too_many_matches(bot, msg, matches, entry): + """if what they did has more than one match give them three tries""" + check = lambda m: m.content.isdigit() + await bot.say('There are too many matches... Which one did you mean? **Only say the number**.') + await bot.say('\n'.join(map(entry, enumerate(matches, 1)))) + + # only give them 3 tries. + for i in range(3): + message = await bot.wait_for_message(author=msg.author, channel=msg.channel, check=check) + index = int(message.content) + try: + return matches[index - 1] + except: + await bot.say('Please give me a valid number. {} tries remaining...'.format(2 - i)) + + raise ValueError('Too many tries. Goodbye.') \ No newline at end of file diff --git a/mod.json b/mod.json new file mode 100644 index 0000000..c1575b9 --- /dev/null +++ b/mod.json @@ -0,0 +1 @@ +{"ignored": []} \ No newline at end of file diff --git a/tapir bot.py b/tapir bot.py index f8f15dc..bd81100 100644 --- a/tapir bot.py +++ b/tapir bot.py @@ -110,4 +110,4 @@ def load_credentials(): handlers = log.handlers[:] for hdlr in handlers: hdlr.close() - log.removeHandler(hdlr) + log.removeHandler(hdlr) \ No newline at end of file diff --git a/tapirs.json b/tapirs.json new file mode 100644 index 0000000..ee724c9 --- /dev/null +++ b/tapirs.json @@ -0,0 +1 @@ +{"tapirs": ["http://i.imgur.com/e18ZHri.png", "http://i.imgur.com/VJDf9s1.png", "http://i.imgur.com/dRAiEe4.png", "http://i.imgur.com/wdova3J.png", "http://i.imgur.com/tJjx4qK.png", "http://i.imgur.com/qeN3TjM.png", "http://i.imgur.com/tHPhFMa.gif", "http://i.imgur.com/WKQiNFw.jpg", "http://i.imgur.com/x4j0d90.jpg", "http://i.imgur.com/Rla6CxQ.jpg", "http://i.imgur.com/TvbXgVi.jpg", "http://i.imgur.com/14P5ikM.jpg", "http://i.imgur.com/ktviJuC.png", "http://i.imgur.com/6994eHI.png", "http://i.imgur.com/5NwpK4M.jpg", "http://i.imgur.com/tpcRmnE.jpg", "http://i.imgur.com/Q3fk7iI.png", "http://i.imgur.com/OXLj8ev.png", "http://i.imgur.com/OYTzAWh.jpg", "http://i.imgur.com/UkBNbfh.png", "http://i.imgur.com/oC8wpfE.png", "http://i.imgur.com/ysuEpzp.png", "http://i.imgur.com/H2LU6Yv.png", "http://i.imgur.com/fnPNxxz.png", "http://i.imgur.com/a6ULF53.png", "http://i.imgur.com/PwodKBZ.png", "http://i.imgur.com/8kzzOoV.png", "http://i.imgur.com/Qurbk2d.png", "http://i.imgur.com/EV4Xr1D.png", "http://i.imgur.com/g2gxNsq.jpg", "http://i.imgur.com/3TTRki4.jpg", "http://i.imgur.com/9MTpv1c.png", "http://i.imgur.com/7zVbBDQ.jpg", "http://i.imgur.com/xncjSd7.png", "http://i.imgur.com/4SiThqS.png", "http://i.imgur.com/A0kOELj.png", "http://i.imgur.com/6BgR8WB.png", "http://i.imgur.com/96Ue3sg.png", "http://i.imgur.com/oFrncNz.png", "http://i.imgur.com/q9KKE6D.png", "http://i.imgur.com/FhXFun1.png", "http://i.imgur.com/mxZtX8j.png", "http://i.imgur.com/BKUUzmO.png", "http://i.imgur.com/S1vKjhl.jpg", "http://i.imgur.com/MWuXrUO.png", "http://i.imgur.com/uzYhQ9W.png", "http://i.imgur.com/HM7oIKc.png", "http://i.imgur.com/ONGCZhO.gif", "http://i.imgur.com/MwgplL8.png", "http://i.imgur.com/R8y3v49.jpg", "http://i.imgur.com/QSC0cSu.png", "http://i.imgur.com/11ZBtG7.png", "http://i.imgur.com/XfyT4H5.gif", "http://i.imgur.com/oLC9AyL.jpg", "http://i.imgur.com/0KVeMLf.jpg", "http://i.imgur.com/MPBZafq.png", "http://i.imgur.com/7g7LHjf.png", "http://i.imgur.com/oxgAUQA.png", "http://i.imgur.com/2W42kNe.jpg", "http://i.imgur.com/KmuiOzA.jpg", "http://i.imgur.com/lGofpCK.jpg", "http://i.imgur.com/pllUFWw.jpg", "http://i.imgur.com/kr2w5TZ.png", "http://i.imgur.com/1nmhYLT.png", "http://i.imgur.com/NfWZFze.png", "http://i.imgur.com/l91ZWw1.png", "http://i.imgur.com/ss1jKr8.png", "http://i.imgur.com/EiYlaVb.png", "http://i.imgur.com/f3jl9Qi.png", "http://i.imgur.com/1jOb6Hb.png", "http://i.imgur.com/dyfC203.png", "http://i.imgur.com/MW4JNJt.png", "http://i.imgur.com/i4lt0Cg.png", "http://i.imgur.com/38qGdwX.png", "http://i.imgur.com/XebMxP5.png", "http://i.imgur.com/qZx3d3D.png", "http://i.imgur.com/vCy8rFr.png", "http://i.imgur.com/Mlywcnm.png", "http://i.imgur.com/Dmc2uM8.jpg", "http://i.imgur.com/9qKB1mk.png", "http://i.imgur.com/SkwJ8KZ.jpg", "http://i.imgur.com/9r35TCm.png", "http://i.imgur.com/WkzM3hh.png", "http://i.imgur.com/VGXNPtU.png", "http://i.imgur.com/fQegjXU.png", "http://i.imgur.com/jaZmvMs.jpg", "http://i.imgur.com/9j63Lov.png", "http://i.imgur.com/9kdYMx5.png", "http://i.imgur.com/R21a14U.png", "http://i.imgur.com/JJobslO.png", "http://i.imgur.com/KNPWux1.gif", "http://i.imgur.com/xxIdm31.gif", "http://i.imgur.com/q3oAWFt.png", "http://i.imgur.com/CYWQnuP.png", "http://i.imgur.com/7QeekYS.png", "http://i.imgur.com/EoUQCCX.png", "http://i.imgur.com/KYfjHot.png", "http://i.imgur.com/JuXH2bj.png", "http://i.imgur.com/A7SxRbS.png", "http://i.imgur.com/NDPnnJt.png", "http://i.imgur.com/5auCaYR.jpg", "http://i.imgur.com/WtepfQT.jpg", "http://i.imgur.com/yyNs8CK.jpg", "http://i.imgur.com/TPkprQp.jpg", "http://i.imgur.com/QKkwMb4.jpg", "http://i.imgur.com/SpTkfSe.png", "http://i.imgur.com/ARkCIh3.png", "http://i.imgur.com/lwgZz3y.jpg", "http://i.imgur.com/WWjdn1y.png", "http://i.imgur.com/YY0vemL.png", "http://i.imgur.com/alDQH24.png", "http://i.imgur.com/YMlJiNe.png", "http://i.imgur.com/7C9zku8.png", "http://i.imgur.com/iPSoLjm.png", "http://i.imgur.com/FCP1Tzq.png", "http://i.imgur.com/vE2XIEy.png", "http://i.imgur.com/aEcshrV.gif", "http://i.imgur.com/PgYNH9a.png", "http://i.imgur.com/TOvEB8a.png", "http://i.imgur.com/vZ4sYdu.png", "http://i.imgur.com/WZE99Mw.png", "http://i.imgur.com/cF5nXWa.jpg", "http://i.imgur.com/NGelpAd.png", "http://i.imgur.com/G3MOhCm.png", "http://i.imgur.com/wmJ7ICc.jpg", "http://i.imgur.com/6jvO9Yr.png", "http://i.imgur.com/F1lqJ87.png", "http://i.imgur.com/aFfDMyX.png", "http://i.imgur.com/tgPoQ9S.jpg", "http://i.imgur.com/n2BjyFA.png", "http://i.imgur.com/Kjza1Q5.png", "http://i.imgur.com/wtepfqt.jpg", "http://i.imgur.com/5ASDULl.png"]} \ No newline at end of file From ce1f02ca1a8970a097901d451245a7124dbff539 Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 18:30:36 -0400 Subject: [PATCH 6/7] Lots of stuff ignores the log file now added a source command to show this added an alias to _quit to support legacy commands hid some commands, unhid others added plonck, which is banning a user from the bot ships cog was made to work added the star_citizen cog with legacy commands made the tapir command work changed some comments changed the help command to `!halp` for interferance pruposes added the logging function for logging stuff --- .gitignore | 3 ++- cogs/meta.py | 7 ++++++- cogs/mod.py | 43 ++++++++++++++++++++++++++++++++++++++++++- cogs/ships.py | 9 ++++++--- cogs/star_citizen.py | 25 +++++++++++++++++++++++++ cogs/tapir.py | 4 +--- cogs/utils/checks.py | 10 +++++----- tapir bot.py | 27 ++++++++++++++++++++++++--- 8 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 cogs/star_citizen.py diff --git a/.gitignore b/.gitignore index 189fdf6..cf550f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/* -*.json +credentials.json *.pyc +*.log diff --git a/cogs/meta.py b/cogs/meta.py index 6fe4559..059f04b 100644 --- a/cogs/meta.py +++ b/cogs/meta.py @@ -19,13 +19,18 @@ async def hello(self): """Displays my hello message.""" await self.bot.say('Hello! I\'m a bot made by <@149281074437029890>') + @commands.command(hidden=True) + async def source(self): + """displays link to github""" + await self.bot.say('Github: https://github.com/treefroog/tapir-bot') + @commands.command(rest_is_raw=True, hidden=True, aliases=['say']) @checks.is_owner() async def echo(self, *, content): """says stuff that I tell it to""" await self.bot.say(content) - @commands.command(name='quit', hidden=True) + @commands.command(name='quit', hidden=True, aliases=['close']) @checks.is_owner() async def _quit(self): """quits tapir-bot""" diff --git a/cogs/mod.py b/cogs/mod.py index 3f83646..cb13316 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -15,7 +15,7 @@ def __init__(self, bot): def bot_user(self, message): return message.server.me if message.channel.is_private else self.bot.user - @commands.group(pass_context=True, no_pm=True) + @commands.group(pass_context=True, no_pm=True, hidden=True) @checks.admin_or_permissions(manage_channels=True) async def ignore(self, ctx): """Handles the bot's ignore lists. @@ -103,5 +103,46 @@ async def unignore(self, ctx, *, channel : discord.Channel = None): else: await self.bot.say('\U0001f44c') + @commands.command(no_pm=True) + @checks.admin_or_permissions(manage_server=True) + async def plonk(self, *, member : discord.Member): + """Bans a user from using the bot. + Note that this ban is **global**. So they are banned from + all servers that they access the bot with. So use this with + caution. + There is no way to bypass a plonk regardless of role or permissions. + The only person who cannot be plonked is the bot creator. So this + must be used with caution. + To use this command you must have the Manage Server permission + or have a Bot Admin role. + """ + + plonks = self.config.get('plonks', []) + if member.id in plonks: + await self.bot.say('That user is already bot banned.') + return + + plonks.append(member.id) + await self.config.put('plonks', plonks) + await self.bot.say('{0.name} has been banned from using the bot.'.format(member)) + + @commands.command(no_pm=True) + @checks.admin_or_permissions(manage_server=True) + async def unplonk(self, *, member : discord.Member): + """Unbans a user from using the bot. + To use this command you must have the Manage Server permission + or have a Bot Admin role. + """ + + plonks = self.config.get('plonks', []) + + try: + plonks.remove(member.id) + except ValueError: + pass + else: + await self.config.put('plonks', plonks) + await self.bot.say('{0.name} has been unbanned from using the bot.'.format(member)) + def setup(bot): bot.add_cog(Mod(bot)) \ No newline at end of file diff --git a/cogs/ships.py b/cogs/ships.py index 0d90eb7..751de2c 100644 --- a/cogs/ships.py +++ b/cogs/ships.py @@ -11,10 +11,13 @@ def __init__(self, bot): @commands.group(pass_context=True) async def ship(self, ctx): - """Posts a link to an album of the specified ship""" + """Posts a link to an album of the specified ship (no where near done)""" if ctx.invoked_subcommand is None: await self.bot.say('Invalid ship: {0.subcommand_passed}'.format(ctx)) - @ship.command(pass_context=True, hidden=True) + @ship.command(pass_context=True) async def carrack(self): - await self.bot.say('Carrack pls http://i.imgur.com/BA3F1OI.png') \ No newline at end of file + await self.bot.say('Carrack pls http://i.imgur.com/BA3F1OI.png') + +def setup(bot): + bot.add_cog(Ships(bot)) \ No newline at end of file diff --git a/cogs/star_citizen.py b/cogs/star_citizen.py new file mode 100644 index 0000000..f3eaab4 --- /dev/null +++ b/cogs/star_citizen.py @@ -0,0 +1,25 @@ +from discord.ext import commands +from .utils import checks +import discord +import asyncio + +class Star_Citizen: + """All of the Star Citizen related commands""" + + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def ben(self): + await self.bot.say('http://i.imgur.com/OLKOQ6H.gif') + + @commands.command() + async def scam(self): + await self.bot.say('Star Citizen is a scam, confirmed by Chris Roberts himself: http://i.imgur.com/UK3D1c0.gifv') + + @commands.command(name='2.4') + async def two_four(self): + await self.bot.say('It\'s not just a meme! http://i.imgur.com/umBUjqW.gif') + +def setup(bot): + bot.add_cog(Star_Citizen(bot)) \ No newline at end of file diff --git a/cogs/tapir.py b/cogs/tapir.py index 1555f1e..bf54b8a 100644 --- a/cogs/tapir.py +++ b/cogs/tapir.py @@ -10,12 +10,10 @@ class Tapir: def __init__(self, bot): self.bot = bot - self.config = config.Config('tapirs.json', loop=bot.loop) - @commands.command() async def tapir(self): """The wonderful tapir command that outputs a random tapir""" - tapir_file = config.Config('tapirs.json', loop=bot.loop) + tapir_file = config.Config('tapirs.json') tapirs = tapir_file.get('tapirs') tapir = tapirs[random.randrange(len(tapirs))] await self.bot.say(tapir) diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 61e646d..76bec8a 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -6,16 +6,16 @@ def is_owner_check(message): return message.author.id == '149281074437029890' def is_owner(): - """is me but diffent""" + """is me but a decorator""" return commands.check(lambda ctx: is_owner_check(ctx.message)) """ There is now a permissions system! if you don't meet a permission to do a command, nothing really happens -but if you are the owner or a so called bot mod you can do stuff +but if you are the owner or a so called bot admin or a server admin or if you are the owner (treefroog) you can do any command -'it just works' --todd howard +"'it just works' +-todd howard" -micheal scott """ @@ -31,7 +31,7 @@ def check_permissions(ctx, perms): return all(getattr(resolved, name, None) == value for name, value in perms.items()) def role_or_permissions(ctx, check, **perms): - """checks roles or permissions, since rolees can do some stuff""" + """checks roles or permissions, since roles can do some stuff""" if check_permissions(ctx, perms): return True diff --git a/tapir bot.py b/tapir bot.py index bd81100..4b58dd2 100644 --- a/tapir bot.py +++ b/tapir bot.py @@ -10,13 +10,16 @@ from collections import Counter description = """ -I am a bot written by treefroog to provide tapirs +I am a bot written by <@149281074437029890> to provide tapirs! \n \nThis is a list of cogs along with their associated commands. """ initial_extensions = [ 'cogs.admin', 'cogs.meta', - 'cogs.mod' + 'cogs.mod', + 'cogs.tapir', + 'cogs.ships', + 'cogs.star_citizen' ] discord_logger = logging.getLogger('discord') @@ -26,12 +29,13 @@ handler = logging.FileHandler(filename='tapir-bot.log', encoding='utf-8', mode='w') log.addHandler(handler) -help_attrs = dict(hidden=True) +help_attrs = dict(hidden=True, name='halp') bot = commands.Bot(command_prefix=['!'], description=description, pm_help=None, help_attrs=help_attrs) @bot.event async def on_command_error(error, ctx): + """some custom error stuff""" if isinstance(error, commands.NoPrivateMessage): await bot.send_message(ctx.message.author, 'This command cannot be used in private messages.') elif isinstance(error, commands.DisabledCommand): @@ -44,6 +48,8 @@ async def on_command_error(error, ctx): @bot.event async def on_ready(): + """what happens when tapir-bot connects to the discord api""" + await bot.change_status(game=discord.Game(name='Say for help!')) print('Logged in as:') print('Username: ' + bot.user.name) print('ID: ' + bot.user.id) @@ -52,9 +58,23 @@ async def on_ready(): print('----------') if not hasattr(bot, 'uptime'): bot.uptime = datetime.datetime.utcnow() + +@bot.event +async def on_command(command, ctx): + """when a command happens it logs it""" + bot.commands_used[command.name] += 1 + message = ctx.message + destination = None + if message.channel.is_private: + destination = 'Private Message' + else: + destination = '#{0.channel.name} ({0.server.name})'.format(message) + + log.info('{0.timestamp}: {0.author.name} in {1}: {0.content}'.format(message, destination)) @bot.event async def on_message(message): + """Some message checking stuff""" if message.author == bot.user: return @@ -90,6 +110,7 @@ async def on_message(message): await bot.process_commands(message) def load_credentials(): + """loads the credentials file with important stuff in it""" with open('credentials.json') as f: return json.load(f) From 5341fee46af7249d11bb784dfe466d0c17ece8b0 Mon Sep 17 00:00:00 2001 From: treefroog Date: Fri, 17 Jun 2016 20:01:23 -0400 Subject: [PATCH 7/7] Few things before release changed the help message made logs "stack" made the game message the help message --- tapir bot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tapir bot.py b/tapir bot.py index 4b58dd2..7c8ee87 100644 --- a/tapir bot.py +++ b/tapir bot.py @@ -10,7 +10,7 @@ from collections import Counter description = """ -I am a bot written by <@149281074437029890> to provide tapirs! \n \nThis is a list of cogs along with their associated commands. +I am a bot written by treefroog to provide tapirs! \n \nThis is a list of cogs along with their associated commands: """ initial_extensions = [ @@ -26,7 +26,7 @@ discord_logger.setLevel(logging.CRITICAL) log = logging.getLogger() log.setLevel(logging.INFO) -handler = logging.FileHandler(filename='tapir-bot.log', encoding='utf-8', mode='w') +handler = logging.FileHandler(filename='tapir-bot.log', encoding='utf-8', mode='r+') log.addHandler(handler) help_attrs = dict(hidden=True, name='halp') @@ -49,7 +49,7 @@ async def on_command_error(error, ctx): @bot.event async def on_ready(): """what happens when tapir-bot connects to the discord api""" - await bot.change_status(game=discord.Game(name='Say for help!')) + await bot.change_status(game=discord.Game(name='Say `!halp` for help!')) print('Logged in as:') print('Username: ' + bot.user.name) print('ID: ' + bot.user.id)