From 0b2ea51df0b43736289fb08235546208dda1f3c1 Mon Sep 17 00:00:00 2001 From: jing1201 Date: Thu, 4 Oct 2018 18:45:54 -0400 Subject: [PATCH 01/27] Added the question command to notify the officers whenever a member has a question --- ALBot.py | 3 ++- cogs/help.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 cogs/help.py diff --git a/ALBot.py b/ALBot.py index ae4c230..64d4564 100644 --- a/ALBot.py +++ b/ALBot.py @@ -15,7 +15,8 @@ "cogs.admin", "cogs.music", "cogs.compile", - "cogs.welcome" + "cogs.welcome", + "cogs.help" ] bot_url = 'https://discordapp.com/api/oauth2/authorize?client_id={0}&scope=bot&permissions=0' diff --git a/cogs/help.py b/cogs/help.py new file mode 100644 index 0000000..4eb56d4 --- /dev/null +++ b/cogs/help.py @@ -0,0 +1,26 @@ +import discord +import random +from discord.ext import commands + +class Help: + '''Commands related to help needed''' + def __init__(self, bot): + self.bot = bot + + ''' + Formats: + !question + !question "[question to be answered]" + ''' + @commands.command() + async def question(self, ctx, q:str = ""): + '''Forward a question to the officer chat''' + member_name = ctx.message.author.name + channel = self.bot.get_channel(436916990238785556) + await channel.send("@everyone\n @"+member_name+" has a question!") + if (q != ""): + await channel.send("\""+q+"\"") + + +def setup(bot): + bot.add_cog(Help(bot)) \ No newline at end of file From 598101779ff3c5d648d043ad03e5ef2481458e57 Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Sun, 7 Oct 2018 15:02:30 -0400 Subject: [PATCH 02/27] Add docker support. Add a dockerfile that builds an image for albot. It just creates an image that installs all the requirements in requirements.txt and then when it runs it mounts the entire project as a volume. --- Dockerfile | 8 ++++++++ docker-compose.yml | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2daf2d2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3-slim-stretch + +WORKDIR /app + +COPY ./requirements.txt . + +RUN apt-get update && apt-get install -y git libopus-dev && \ + pip install --trusted-host pypi.python.org -r requirements.txt diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9964544 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: '3' + +services: + albot: + build: . + volumes: + - .:/app + command: python -u ALBot.py From f7f6a6eb138232732be3d3d3b231fffd98c67517 Mon Sep 17 00:00:00 2001 From: jing1201 Date: Thu, 11 Oct 2018 17:57:44 -0400 Subject: [PATCH 03/27] Updated help.py for command question to accept argument with variable length --- cogs/help.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cogs/help.py b/cogs/help.py index 4eb56d4..bdb6993 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -7,14 +7,14 @@ class Help: def __init__(self, bot): self.bot = bot - ''' - Formats: - !question - !question "[question to be answered]" - ''' + @commands.command() - async def question(self, ctx, q:str = ""): - '''Forward a question to the officer chat''' + async def question(self, ctx, *, q : str = ""): + ''' Forward a question to the officer chat + Formats: + !question + !question [question to be answered] + ''' member_name = ctx.message.author.name channel = self.bot.get_channel(436916990238785556) await channel.send("@everyone\n @"+member_name+" has a question!") From 7e65f305eeefd693b88d7be3f0af7450881ff8af Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Thu, 11 Oct 2018 18:50:23 -0400 Subject: [PATCH 04/27] Add ffmpeg to Dockerfile. Add ffmpeg to docker for the play music commands to function. --- .gitignore | 1 + Dockerfile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e259196..bfd4ada 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ *.jpg config.py database/data/sqlite3.db +.idea/ diff --git a/Dockerfile b/Dockerfile index 2daf2d2..4bf3182 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,5 +4,5 @@ WORKDIR /app COPY ./requirements.txt . -RUN apt-get update && apt-get install -y git libopus-dev && \ +RUN apt-get update && apt-get install -y git ffmpeg libopus-dev && \ pip install --trusted-host pypi.python.org -r requirements.txt From 8cb5678f42c5f70caf49e8d7836be4d846a6573c Mon Sep 17 00:00:00 2001 From: jing1201 Date: Thu, 25 Oct 2018 20:19:49 -0400 Subject: [PATCH 05/27] Added the reminder function to remind officers to book rooms --- ALBot.py | 7 ++++--- cogs/reminder.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 cogs/reminder.py diff --git a/ALBot.py b/ALBot.py index 64d4564..4b9aec3 100644 --- a/ALBot.py +++ b/ALBot.py @@ -16,7 +16,8 @@ "cogs.music", "cogs.compile", "cogs.welcome", - "cogs.help" + "cogs.help", + "cogs.reminder" ] bot_url = 'https://discordapp.com/api/oauth2/authorize?client_id={0}&scope=bot&permissions=0' @@ -39,5 +40,5 @@ async def on_ready(): except Exception as e: exc = '{}: {}'.format(type(e).__name__, e) print('Failed to load extension {}\n{}'.format(extension, exc)) - -bot.run(config.ALBOT_TOKEN) + +bot.run(config.ALBOT_TOKEN) \ No newline at end of file diff --git a/cogs/reminder.py b/cogs/reminder.py new file mode 100644 index 0000000..db8327a --- /dev/null +++ b/cogs/reminder.py @@ -0,0 +1,32 @@ +import discord +import random +import datetime +import asyncio +from discord.ext import commands + +class Reminder: + '''To remind officers and members about things''' + def __init__(self, bot): + self.bot = bot + self.book_room_bg_task = self.bot.loop.create_task(self.book_room_reminder()) + + async def book_room_reminder(self): + await self.bot.wait_until_ready() + channel = self.bot.get_channel(436916990238785556) + while True: + current_day_of_the_week = (str)(datetime.date.today().strftime("%A")) + #print (current_day_of_the_week) + if current_day_of_the_week == "Wednesday" or current_day_of_the_week == "Thursday": + await channel.send("@everyone Reminder to book rooms!") + # ideally, the bot would send the reminder on Wednesdat 12am, + # but to account for when the bot starts running, + # the time below is 2 minutes less than 1 week, + # this allows the time to be slowly adjusted every week until it reaches 12am + await asyncio.sleep(604680) # a little less than a week + else: + # this line will run twice every week once + # the time is stabilized as mentioned above + await asyncio.sleep(60) # check every 1 minute + +def setup(bot): + bot.add_cog(Reminder(bot)) \ No newline at end of file From a1b91dae6618056f052820dcb0dbee7b79d5d4c7 Mon Sep 17 00:00:00 2001 From: jing1201 Date: Thu, 25 Oct 2018 22:04:08 -0400 Subject: [PATCH 06/27] Added ARM to helloworld languages (because we all love ARM) --- cogs/helloworld/arm.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 cogs/helloworld/arm.txt diff --git a/cogs/helloworld/arm.txt b/cogs/helloworld/arm.txt new file mode 100644 index 0000000..a333259 --- /dev/null +++ b/cogs/helloworld/arm.txt @@ -0,0 +1,18 @@ +```arm +.data +outformat: .asciz "%s" +string: .asciz "Hello, World!\n" + +.text +.global main + +main: ldr x0, =outformat + ldr x1, =string + bl printf + + b exit + +exit: mov x0, #0 + mov x8, #93 + svc #0 +``` \ No newline at end of file From f111efaf4238736a5f426582b07aa3707a4e8696 Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Fri, 16 Nov 2018 11:57:58 -0500 Subject: [PATCH 07/27] Sends first when new channels are created. Why not? Closes #27 --- cogs/memes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cogs/memes.py b/cogs/memes.py index 05031e1..18834da 100644 --- a/cogs/memes.py +++ b/cogs/memes.py @@ -48,5 +48,9 @@ async def say(self, ctx, *, phrase : str): '''Has the bot say something''' await ctx.send(phrase) + async def on_guild_channel_create(self, channel): + '''Messages "First" when a channel is created''' + await channel.send('First') + def setup(bot): bot.add_cog(Memes(bot)) From 61a871fa5d6d48eaca3d38b3496353a12061e5fd Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 14 Mar 2019 14:15:54 -0400 Subject: [PATCH 08/27] Added Cog inheritance and listeners --- ALBot.py | 4 ++-- cogs/admin.py | 5 +++++ cogs/compile.py | 4 ++++ cogs/errors.py | 14 ++++++++++++++ cogs/helloworld.py | 4 ++++ cogs/help.py | 26 ++++++++++++++++++++++++++ cogs/memes.py | 11 +++++++++++ cogs/messages.py | 3 ++- cogs/music.py | 4 ++++ cogs/projects.py | 4 ++++ cogs/reminder.py | 32 ++++++++++++++++++++++++++++++++ cogs/welcome.py | 4 ++++ 12 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 cogs/help.py create mode 100644 cogs/reminder.py diff --git a/ALBot.py b/ALBot.py index ae4c230..40f042c 100644 --- a/ALBot.py +++ b/ALBot.py @@ -38,5 +38,5 @@ async def on_ready(): except Exception as e: exc = '{}: {}'.format(type(e).__name__, e) print('Failed to load extension {}\n{}'.format(extension, exc)) - -bot.run(config.ALBOT_TOKEN) + +bot.run(config.ALBOT_TOKEN) \ No newline at end of file diff --git a/cogs/admin.py b/cogs/admin.py index fef47fc..fe15304 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -7,7 +7,12 @@ import cogs.util +<<<<<<< HEAD class Admin: +======= + +class Admin(commands.Cog, name="Admin"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. def __init__(self, bot): self.bot = bot diff --git a/cogs/compile.py b/cogs/compile.py index 0bc50ff..282d9ba 100644 --- a/cogs/compile.py +++ b/cogs/compile.py @@ -5,7 +5,11 @@ import cogs.util +<<<<<<< HEAD class Compile: +======= +class Compile(commands.Cog, name="Compile"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. def __init__(self, bot): self.bot = bot self.complangs = [] diff --git a/cogs/errors.py b/cogs/errors.py index 8967576..6c31208 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -9,7 +9,11 @@ from database.database import SQLCursor, SQLConnection from cogs.messages import track +<<<<<<< HEAD class ALBotErrorHandlers: +======= +class ALBotErrorHandlers(commands.Cog, name = "Error Handler"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. """ Handles errors """ def __init__(self, bot, db): @@ -69,7 +73,12 @@ async def on_command_error(self, ctx, error): bt_string = ''.join(traceback.format_exception(type(error), error, error.__traceback__)) print('{bname} encountered an error:\n{0}'.format(bt_string, bname=CONSTANTS.BOT_NAME)) cur.execute('INSERT INTO error_messages (message_id, channel_id, command_name, error_name, error_text, full_backtrace, full_command_string) VALUES (?,?,?,?,?,?,?);',(msg.id, msg.channel.id, ctx.command.name, str(type(error)), str(error), bt_string, ctx.message.content)) +<<<<<<< HEAD +======= + + @commands.Cog.listener() +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. async def on_raw_reaction_add(self, payload): if payload.user_id == self.bot.user.id: return @@ -84,7 +93,12 @@ async def on_raw_reaction_add(self, payload): to_edit = await self.bot.get_channel(payload.channel_id).get_message(payload.message_id) new_embed = self._construct_error_embed(row[0],row[1],row[2],row[3],row[4]) await to_edit.edit(content='{err} Command error {err}'.format(err=CONSTANTS.REACTION_ERROR),embed=new_embed) +<<<<<<< HEAD +======= + + @commands.Cog.listener() +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. async def on_raw_reaction_remove(self, payload): if payload.user_id == self.bot.user.id: return diff --git a/cogs/helloworld.py b/cogs/helloworld.py index a6e2016..78f3776 100644 --- a/cogs/helloworld.py +++ b/cogs/helloworld.py @@ -2,7 +2,11 @@ from discord.ext import commands import os +<<<<<<< HEAD class HelloWorld: +======= +class HelloWorld(commands.Cog, name = "Hello World"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. '''Discord.py Cog for printing the hello world code for different languages''' def __init__(self, bot): diff --git a/cogs/help.py b/cogs/help.py new file mode 100644 index 0000000..bdb6993 --- /dev/null +++ b/cogs/help.py @@ -0,0 +1,26 @@ +import discord +import random +from discord.ext import commands + +class Help: + '''Commands related to help needed''' + def __init__(self, bot): + self.bot = bot + + + @commands.command() + async def question(self, ctx, *, q : str = ""): + ''' Forward a question to the officer chat + Formats: + !question + !question [question to be answered] + ''' + member_name = ctx.message.author.name + channel = self.bot.get_channel(436916990238785556) + await channel.send("@everyone\n @"+member_name+" has a question!") + if (q != ""): + await channel.send("\""+q+"\"") + + +def setup(bot): + bot.add_cog(Help(bot)) \ No newline at end of file diff --git a/cogs/memes.py b/cogs/memes.py index 05031e1..a509e98 100644 --- a/cogs/memes.py +++ b/cogs/memes.py @@ -4,7 +4,11 @@ import cogs.util +<<<<<<< HEAD class Memes: +======= +class Memes(commands.Cog, name = "Memes"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. '''All meme related commands''' def __init__(self, bot): @@ -48,5 +52,12 @@ async def say(self, ctx, *, phrase : str): '''Has the bot say something''' await ctx.send(phrase) +<<<<<<< HEAD +======= + async def on_guild_channel_create(self, channel): + '''Messages "First" when a channel is created''' + await channel.send('First') + +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. def setup(bot): bot.add_cog(Memes(bot)) diff --git a/cogs/messages.py b/cogs/messages.py index c1360e8..a9af396 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -4,12 +4,13 @@ import cogs.CONSTANTS as CONSTANTS from database.database import SQLCursor, SQLConnection -class ALBotMessageDeletionHandlers: +class ALBotMessageDeletionHandlers(commands.Cog, name='Message Deletion Handlers'): """ Functions for handling tracked messages """ def __init__(self, bot, db): self.bot = bot self.db = db + @commands.Cog.listener() async def on_raw_reaction_add(self, payload): """ Checks reactions and deletes tracked messages when necessary. """ if payload.user_id == self.bot.user.id: diff --git a/cogs/music.py b/cogs/music.py index fe98694..1e4ca9f 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -9,7 +9,11 @@ import asyncio import youtube_dl +<<<<<<< HEAD class VoiceEntry: +======= +class VoiceEntry(commands.Cog, name="Voice Entry"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. '''A class that represents a song that can be played''' def __init__(self, message, player, title, uploader, duration): self.requester = message.author diff --git a/cogs/projects.py b/cogs/projects.py index 008297d..9a8cd95 100644 --- a/cogs/projects.py +++ b/cogs/projects.py @@ -2,7 +2,11 @@ from discord.utils import get from discord.ext import commands +<<<<<<< HEAD class Projects: +======= +class Projects(commands.Cog, name="Projects"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. '''Commands dealing with the different projects we are working on''' def __init__(self, bot): diff --git a/cogs/reminder.py b/cogs/reminder.py new file mode 100644 index 0000000..db8327a --- /dev/null +++ b/cogs/reminder.py @@ -0,0 +1,32 @@ +import discord +import random +import datetime +import asyncio +from discord.ext import commands + +class Reminder: + '''To remind officers and members about things''' + def __init__(self, bot): + self.bot = bot + self.book_room_bg_task = self.bot.loop.create_task(self.book_room_reminder()) + + async def book_room_reminder(self): + await self.bot.wait_until_ready() + channel = self.bot.get_channel(436916990238785556) + while True: + current_day_of_the_week = (str)(datetime.date.today().strftime("%A")) + #print (current_day_of_the_week) + if current_day_of_the_week == "Wednesday" or current_day_of_the_week == "Thursday": + await channel.send("@everyone Reminder to book rooms!") + # ideally, the bot would send the reminder on Wednesdat 12am, + # but to account for when the bot starts running, + # the time below is 2 minutes less than 1 week, + # this allows the time to be slowly adjusted every week until it reaches 12am + await asyncio.sleep(604680) # a little less than a week + else: + # this line will run twice every week once + # the time is stabilized as mentioned above + await asyncio.sleep(60) # check every 1 minute + +def setup(bot): + bot.add_cog(Reminder(bot)) \ No newline at end of file diff --git a/cogs/welcome.py b/cogs/welcome.py index 1f81669..95ca358 100644 --- a/cogs/welcome.py +++ b/cogs/welcome.py @@ -3,7 +3,11 @@ from discord.ext import commands import config +<<<<<<< HEAD class Welcome: +======= +class Welcome(commands.Cog, name="Welcome"): +>>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. '''To automatically welcome new members to the server''' def __init__(self, bot): From 58c70010f6ed45942ac0b04f07e8488806e60b3c Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 14 Mar 2019 14:19:42 -0400 Subject: [PATCH 09/27] Added factorial support. --- .gitignore | 2 ++ cogs/messages.py | 25 +++++++++++++++++++++++++ cogs/projects.py | 4 ---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index e259196..3d0d3d9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ __pycache__/ *.jpg config.py database/data/sqlite3.db + +\.idea/ diff --git a/cogs/messages.py b/cogs/messages.py index a9af396..f7fc204 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -10,6 +10,31 @@ def __init__(self, bot, db): self.bot = bot self.db = db + @commands.Cog.listener() + async def on_message(self, msg): + """Checks message for factorial format using regex.""" + if msg.author != self.bot.user: + import re + filtered_msg = re.findall('{(?:[0-9]|[1-8](?:[0-9]{1,2})?)!}', + msg.content) + if filtered_msg is not None: + group_len = len(filtered_msg) + print('Groups: ' + str(group_len)) + factorial = 'Factorial: `{}! = {}`' if group_len == 1 else 'The following factorials were calculated as:```' + import math + if group_len > 1: + for i in range(0, group_len): + num = int((filtered_msg[i].split('!')[0])[1:]) + product = math.factorial(num) + factorial += '\n\n{}! = {}'.format(num, product) + await msg.channel.send(factorial + '```') + elif group_len == 1: + num = int((filtered_msg[0].split('!')[0])[1:]) + await msg.channel.send( + factorial.format(num, math.factorial(num))) + + await self.bot.process_commands(msg) + @commands.Cog.listener() async def on_raw_reaction_add(self, payload): """ Checks reactions and deletes tracked messages when necessary. """ diff --git a/cogs/projects.py b/cogs/projects.py index 9a8cd95..008297d 100644 --- a/cogs/projects.py +++ b/cogs/projects.py @@ -2,11 +2,7 @@ from discord.utils import get from discord.ext import commands -<<<<<<< HEAD class Projects: -======= -class Projects(commands.Cog, name="Projects"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. '''Commands dealing with the different projects we are working on''' def __init__(self, bot): From 88eef6666340dc0a0692cb395bf6ecf70e8ffaa1 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 15 Mar 2019 16:50:35 -0400 Subject: [PATCH 10/27] Cog inheritance and listener decorators --- ALBot.py | 4 ++-- cogs/admin.py | 15 +++++---------- cogs/compile.py | 13 +++++-------- cogs/errors.py | 17 ++++------------- cogs/helloworld.py | 13 ++++--------- cogs/help.py | 11 +++++------ cogs/memes.py | 27 ++++++++++----------------- cogs/messages.py | 26 -------------------------- cogs/music.py | 11 ++++------- cogs/projects.py | 5 ++--- cogs/reminder.py | 6 +++--- cogs/util.py | 4 ++-- cogs/welcome.py | 9 ++------- database/INFO.md | 6 +++--- 14 files changed, 51 insertions(+), 116 deletions(-) diff --git a/ALBot.py b/ALBot.py index 40f042c..dcb70c7 100644 --- a/ALBot.py +++ b/ALBot.py @@ -5,7 +5,7 @@ import cogs.CONSTANTS as CONSTANTS import config -'''Cogs to load when the bot first starts''' +"""Cogs to load when the bot first starts""" startup_cogs = [ "cogs.messages", "cogs.errors", @@ -39,4 +39,4 @@ async def on_ready(): exc = '{}: {}'.format(type(e).__name__, e) print('Failed to load extension {}\n{}'.format(extension, exc)) -bot.run(config.ALBOT_TOKEN) \ No newline at end of file +bot.run(config.ALBOT_TOKEN) diff --git a/cogs/admin.py b/cogs/admin.py index fe15304..3e55b97 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -7,12 +7,7 @@ import cogs.util -<<<<<<< HEAD -class Admin: -======= - -class Admin(commands.Cog, name="Admin"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. +class Admin(commands.Cog, name='Admin'): def __init__(self, bot): self.bot = bot @@ -20,7 +15,7 @@ def __init__(self, bot): @commands.command(hidden=True) @commands.check(cogs.util.is_officer_check) async def load(self, ctx, extension_name : str): - '''Loads an extension.''' + """Loads an extension.""" try: if extension_name.startswith("cogs."): self.bot.load_extension(extension_name) @@ -44,7 +39,7 @@ async def unload(self, ctx, extension_name : str): @commands.command(hidden=True) @commands.check(cogs.util.is_officer_check) async def reload(self, ctx, extension_name : str): - '''Unloads and then loads an extension''' + """Unloads and then loads an extension""" try: if extension_name.startswith("cogs."): self.bot.unload_extension(extension_name) @@ -65,7 +60,7 @@ async def whereami(self, ctx): @commands.command(hidden=True, name="eval") @commands.check(cogs.util.is_owner) async def admin_eval(self, ctx, *, cmd : str): - '''Evaluates Python code only if the executor is hjarrell''' + """Evaluates Python code only if the executor is hjarrell""" env = { 'bot': self.bot, 'discord': discord, @@ -88,7 +83,7 @@ async def admin_eval(self, ctx, *, cmd : str): ret = await eval("__admin_eval()", env) except Exception as e: value = stdout.getvalue() - await ctx.send("```py\n{value}{e}\n```".format()) + await ctx.send("```py\n{}{}\n```".format(value, e)) else: value = stdout.getvalue() if ret is None: diff --git a/cogs/compile.py b/cogs/compile.py index 282d9ba..f005eff 100644 --- a/cogs/compile.py +++ b/cogs/compile.py @@ -5,11 +5,8 @@ import cogs.util -<<<<<<< HEAD -class Compile: -======= -class Compile(commands.Cog, name="Compile"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. +class Compile(commands.Cog, name='Compile'): + def __init__(self, bot): self.bot = bot self.complangs = [] @@ -17,7 +14,7 @@ def __init__(self, bot): @commands.command(name="complangs") async def compile_langs(self, ctx): - '''Get the languages and ids for compiling code''' + """Get the languages and ids for compiling code""" if len(self.complangs) == 0: langs = requests.get("https://api.judge0.com/languages") @@ -31,7 +28,7 @@ async def compile_langs(self, ctx): @commands.command(name="compile") async def _compile(self, ctx, lang_id : int, *, program : str): - '''Compiles and runs code using the judge0 api''' + """Compiles and runs code using the judge0 api""" payload = {'source_code' : program, 'language_id' : lang_id} headers = {'Content-Type': "application/json"} r = requests.post("https://api.judge0.com/submissions/?base64_encoded=false&wait=true", data=json.dumps(payload), headers=headers) @@ -47,7 +44,7 @@ async def _compile(self, ctx, lang_id : int, *, program : str): @commands.command(name="compdebug") @commands.check(cogs.util.is_officer_check) async def debug_compile(self, ctx): - '''Toggles whether to print the full compile output''' + """Toggles whether to print the full compile output""" self.is_debug = not self.is_debug await ctx.send("is_debugging = {}".format(self.is_debug)) diff --git a/cogs/errors.py b/cogs/errors.py index 6c31208..5b6d2c5 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -9,13 +9,8 @@ from database.database import SQLCursor, SQLConnection from cogs.messages import track -<<<<<<< HEAD -class ALBotErrorHandlers: -======= -class ALBotErrorHandlers(commands.Cog, name = "Error Handler"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. +class ALBotErrorHandlers(commands.Cog, name='Error Handler'): """ Handles errors """ - def __init__(self, bot, db): self.bot = bot self.db = db @@ -73,12 +68,12 @@ async def on_command_error(self, ctx, error): bt_string = ''.join(traceback.format_exception(type(error), error, error.__traceback__)) print('{bname} encountered an error:\n{0}'.format(bt_string, bname=CONSTANTS.BOT_NAME)) cur.execute('INSERT INTO error_messages (message_id, channel_id, command_name, error_name, error_text, full_backtrace, full_command_string) VALUES (?,?,?,?,?,?,?);',(msg.id, msg.channel.id, ctx.command.name, str(type(error)), str(error), bt_string, ctx.message.content)) -<<<<<<< HEAD + -======= + @commands.Cog.listener() ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. + async def on_raw_reaction_add(self, payload): if payload.user_id == self.bot.user.id: return @@ -93,12 +88,8 @@ async def on_raw_reaction_add(self, payload): to_edit = await self.bot.get_channel(payload.channel_id).get_message(payload.message_id) new_embed = self._construct_error_embed(row[0],row[1],row[2],row[3],row[4]) await to_edit.edit(content='{err} Command error {err}'.format(err=CONSTANTS.REACTION_ERROR),embed=new_embed) -<<<<<<< HEAD - -======= @commands.Cog.listener() ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. async def on_raw_reaction_remove(self, payload): if payload.user_id == self.bot.user.id: return diff --git a/cogs/helloworld.py b/cogs/helloworld.py index 78f3776..95f44cb 100644 --- a/cogs/helloworld.py +++ b/cogs/helloworld.py @@ -2,19 +2,14 @@ from discord.ext import commands import os -<<<<<<< HEAD -class HelloWorld: -======= -class HelloWorld(commands.Cog, name = "Hello World"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. - '''Discord.py Cog for printing the hello world code for different languages''' - +class HelloWorld(commands.Cog, name='Hello World'): + """Discord.py Cog for printing the hello world code for different languages""" def __init__(self, bot): self.bot = bot @commands.command() async def hello(self, ctx, lang : str): - '''Prints the hello world source for any language defined in cogs/helloworld''' + """Prints the hello world source for any language defined in cogs/helloworld""" for fName in os.listdir("cogs/helloworld"): if fName == (lang.lower() + ".txt"): with open("cogs/helloworld/{}".format(fName), 'r') as f: @@ -22,7 +17,7 @@ async def hello(self, ctx, lang : str): @commands.command() async def hellolangs(self, ctx): - '''Prints all the languages that there are helloworld's for''' + """Prints all the languages that there are helloworld's for""" langs = '' for fName in os.listdir("cogs/helloworld"): langs += fName.replace('.txt','') + '\n' diff --git a/cogs/help.py b/cogs/help.py index bdb6993..4c0ff51 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -2,19 +2,18 @@ import random from discord.ext import commands -class Help: - '''Commands related to help needed''' +class Help(commands.Cog, name='Help'): + """Commands related to help needed""" def __init__(self, bot): self.bot = bot - @commands.command() async def question(self, ctx, *, q : str = ""): - ''' Forward a question to the officer chat + """ Forward a question to the officer chat Formats: !question !question [question to be answered] - ''' + """ member_name = ctx.message.author.name channel = self.bot.get_channel(436916990238785556) await channel.send("@everyone\n @"+member_name+" has a question!") @@ -23,4 +22,4 @@ async def question(self, ctx, *, q : str = ""): def setup(bot): - bot.add_cog(Help(bot)) \ No newline at end of file + bot.add_cog(Help(bot)) diff --git a/cogs/memes.py b/cogs/memes.py index a509e98..8b6a069 100644 --- a/cogs/memes.py +++ b/cogs/memes.py @@ -4,13 +4,8 @@ import cogs.util -<<<<<<< HEAD -class Memes: -======= -class Memes(commands.Cog, name = "Memes"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. - '''All meme related commands''' - +class Memes(commands.Cog, name='Memes'): + """All meme related commands""" def __init__(self, bot): self.bot = bot self.playing_strings = [] @@ -19,24 +14,24 @@ def __init__(self, bot): @commands.command() async def orange(self, ctx): - '''Responds to the classic football chant "Orange" "Blue"''' + """Responds to the classic football chant "Orange" "Blue""" await ctx.send("BLUE!") @commands.command() async def blue(self, ctx): - '''Responds to the classic football chant "Orange" "Blue"''' + """Responds to the classic football chant "Orange" "Blue""" await ctx.send("ORANGE!") @commands.command() async def about(self, ctx): - '''Prints information about the bots.''' + """Prints information about the bots.""" await ctx.send("We are your benevolent dictators. Fear us.") await ctx.send(file=discord.File('alligator.jpg')) @commands.command() @commands.check(cogs.util.is_officer_check) async def randplaying(self, ctx): - '''Randomly changes the playing text''' + """Randomly changes the playing text""" new_playing = random.choice(self.playing_strings) await self.bot.change_presence(activity=discord.Game(name=new_playing)) await ctx.send('I am now {}'.format(new_playing)) @@ -44,20 +39,18 @@ async def randplaying(self, ctx): @commands.command() @commands.check(cogs.util.is_officer_check) async def setplaying(self, ctx, *, playing: str): - '''Lets an officer set the playing text''' + """Lets an officer set the playing text""" await self.bot.change_presence(activity=discord.Game(name=playing)) @commands.command() async def say(self, ctx, *, phrase : str): - '''Has the bot say something''' + """Has the bot say something""" await ctx.send(phrase) -<<<<<<< HEAD -======= async def on_guild_channel_create(self, channel): - '''Messages "First" when a channel is created''' + """Messages "First" when a channel is created""" await channel.send('First') ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. + def setup(bot): bot.add_cog(Memes(bot)) diff --git a/cogs/messages.py b/cogs/messages.py index f7fc204..abe6677 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -10,31 +10,6 @@ def __init__(self, bot, db): self.bot = bot self.db = db - @commands.Cog.listener() - async def on_message(self, msg): - """Checks message for factorial format using regex.""" - if msg.author != self.bot.user: - import re - filtered_msg = re.findall('{(?:[0-9]|[1-8](?:[0-9]{1,2})?)!}', - msg.content) - if filtered_msg is not None: - group_len = len(filtered_msg) - print('Groups: ' + str(group_len)) - factorial = 'Factorial: `{}! = {}`' if group_len == 1 else 'The following factorials were calculated as:```' - import math - if group_len > 1: - for i in range(0, group_len): - num = int((filtered_msg[i].split('!')[0])[1:]) - product = math.factorial(num) - factorial += '\n\n{}! = {}'.format(num, product) - await msg.channel.send(factorial + '```') - elif group_len == 1: - num = int((filtered_msg[0].split('!')[0])[1:]) - await msg.channel.send( - factorial.format(num, math.factorial(num))) - - await self.bot.process_commands(msg) - @commands.Cog.listener() async def on_raw_reaction_add(self, payload): """ Checks reactions and deletes tracked messages when necessary. """ @@ -69,6 +44,5 @@ async def track(message, author=None): with SQLCursor(sql_db) as cur: cur.execute("INSERT INTO tracked_messages (messid, sender_uid, track_time) VALUES (?, ?, ?);", (message.id, aid, message.created_at)) - def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) diff --git a/cogs/music.py b/cogs/music.py index 1e4ca9f..f7a7133 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -9,12 +9,9 @@ import asyncio import youtube_dl -<<<<<<< HEAD class VoiceEntry: -======= -class VoiceEntry(commands.Cog, name="Voice Entry"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. - '''A class that represents a song that can be played''' + + """A class that represents a song that can be played""" def __init__(self, message, player, title, uploader, duration): self.requester = message.author self.channel = message.channel @@ -30,7 +27,7 @@ def __str__(self): return fmt.format(self.title, self.uploader, self.requester) class VoiceState: - '''Holds the queued song and players for a guild server''' + """Holds the queued song and players for a guild server""" def __init__(self, bot): self.current = None self.voice = None @@ -69,7 +66,7 @@ async def audio_player_task(self): self.voice.play(self.current.player) await self.play_next_song.wait() -class Music: +class Music(commands.Cog, name='Music'): """Voice related commands. Works in multiple servers at once. """ diff --git a/cogs/projects.py b/cogs/projects.py index 008297d..31388f2 100644 --- a/cogs/projects.py +++ b/cogs/projects.py @@ -2,9 +2,8 @@ from discord.utils import get from discord.ext import commands -class Projects: - '''Commands dealing with the different projects we are working on''' - +class Projects(commands.Cog, name='Projects'): + """Commands dealing with the different projects we are working on""" def __init__(self, bot): self.bot = bot diff --git a/cogs/reminder.py b/cogs/reminder.py index db8327a..e50c169 100644 --- a/cogs/reminder.py +++ b/cogs/reminder.py @@ -4,8 +4,8 @@ import asyncio from discord.ext import commands -class Reminder: - '''To remind officers and members about things''' +class Reminder(commands.Cog, name='Reminder'): + """To remind officers and members about things""" def __init__(self, bot): self.bot = bot self.book_room_bg_task = self.bot.loop.create_task(self.book_room_reminder()) @@ -29,4 +29,4 @@ async def book_room_reminder(self): await asyncio.sleep(60) # check every 1 minute def setup(bot): - bot.add_cog(Reminder(bot)) \ No newline at end of file + bot.add_cog(Reminder(bot)) diff --git a/cogs/util.py b/cogs/util.py index 15d2068..d30e79a 100644 --- a/cogs/util.py +++ b/cogs/util.py @@ -1,9 +1,9 @@ import discord def is_officer_check(ctx): - '''Check to see if the author is an officer''' + """Check to see if the author is an officer""" return discord.utils.get(ctx.message.author.roles, name='officer') is not None def is_owner(ctx): - '''Check to see if the author is an hjarrell''' + """Check to see if the author is an hjarrell""" return ctx.message.author.id == 402565484072927235 diff --git a/cogs/welcome.py b/cogs/welcome.py index 95ca358..f1896c6 100644 --- a/cogs/welcome.py +++ b/cogs/welcome.py @@ -3,18 +3,13 @@ from discord.ext import commands import config -<<<<<<< HEAD -class Welcome: -======= class Welcome(commands.Cog, name="Welcome"): ->>>>>>> parent of 1e08d60... Fixed cog inheritance and added factorial support. - '''To automatically welcome new members to the server''' - + """To automatically welcome new members to the server""" def __init__(self, bot): self.bot = bot async def on_member_join(self, member): - fmt = '''Welcome {0.mention}! \nFeel free to use \"!question\" to let us know if you have any questions \nAnd you can also use \"!help\", all in the #bot-spam channel to find out about what you can do with our Discord bot ALBot :D ''' + fmt = """Welcome {0.mention}! \nFeel free to use \"!question\" to let us know if you have any questions \nAnd you can also use \"!help\", all in the #bot-spam channel to find out about what you can do with our Discord bot ALBot :D """ dm_channel = member.dm_channel if dm_channel == None: await member.create_dm() diff --git a/database/INFO.md b/database/INFO.md index 5befa74..0c8b9cc 100644 --- a/database/INFO.md +++ b/database/INFO.md @@ -12,7 +12,7 @@ from sql.sql import SQLConnection, SQLCursor, SQLRollback connection = SQLConnection() # Checks the database integrity and returns a new connection object with SQLCursor(connection) as cursor: # The backend uses a context manager to wrap the cursor object - ''' Get data from some_table ''' + """ Get data from some_table """ cursor.execute('SELECT * FROM some_table;') result = cursor.fetchall() @@ -24,7 +24,7 @@ with SQLCursor(connection) as cursor: # The backend uses a context manager to wr some_message_id = 484572171608522771 some_message_text = 'The Spanish Inquisition' with SQLCursor(connection) as cursor: - ''' Insert values into some_table, sanitizing them to prevent naughty business. ''' + """ Insert values into some_table, sanitizing them to prevent naughty business. """ cursor.execute('INSERT INTO some_table (message_id, message_text) VALUES (?,?);', (some_message_id, some_message_text)) print('done') # Changes are automatically committed at the end of the 'with' statement. @@ -37,7 +37,7 @@ some_message_text = 'My most embarassing secrets that I would never want in an S message_is_regretted = True with SQLCursor(connection) as cursor: - ''' Insert a value, then roll it back ''' + """ Insert a value, then roll it back """ cursor.execute('INSERT INTO some_table (message_id, message_text) VALUES (?, ?);', (some_message_id, some_message_text)) if message_is_regretted: From 3b9cc9cf651f43a4d3683af594dc0c976116f68f Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 15 Mar 2019 16:51:06 -0400 Subject: [PATCH 11/27] Factorial support --- cogs/messages.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cogs/messages.py b/cogs/messages.py index abe6677..ff936f4 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -44,5 +44,36 @@ async def track(message, author=None): with SQLCursor(sql_db) as cur: cur.execute("INSERT INTO tracked_messages (messid, sender_uid, track_time) VALUES (?, ?, ?);", (message.id, aid, message.created_at)) +class ALBotFactorialHandler(commands.Cog, name='Factorial Handler'): + + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_message(self, msg): + """Checks message for factorial format using regex.""" + if msg.author != self.bot.user: + import re + filtered_msg = re.findall('{(?:[0-9]|[1-8](?:[0-9]{1,2})?)!}', msg.content) + if filtered_msg is not None: + group_len = len(filtered_msg) + factorial = 'Factorial: `{}! = {}`' if group_len == 1 else 'The following factorials were calculated as:```' + import math + if group_len > 1: + for i in range(0, group_len): + num = int((filtered_msg[i].split('!')[0])[1:]) + product = math.factorial(num) + factorial += '\n\n{}! = {}'.format(num, product) + await msg.channel.send(factorial + '```') + elif group_len == 1: + try: + num = int((filtered_msg[0].split('!')[0])[1:]) + await msg.channel.send(factorial.format(num, math.factorial(num))) + except discord.HTTPException as e: + await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') + + await self.bot.process_commands(msg) + def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) + bot.add_cog(ALBotFactorialHandler(bot)) From 3275ecca668df2e534dfd84332cf4c497b264d6d Mon Sep 17 00:00:00 2001 From: swiftlee Date: Sat, 16 Mar 2019 10:53:25 -0400 Subject: [PATCH 12/27] Fixed whitespace issue on decorator --- cogs/errors.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cogs/errors.py b/cogs/errors.py index 5b6d2c5..4cb285e 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -69,11 +69,7 @@ async def on_command_error(self, ctx, error): print('{bname} encountered an error:\n{0}'.format(bt_string, bname=CONSTANTS.BOT_NAME)) cur.execute('INSERT INTO error_messages (message_id, channel_id, command_name, error_name, error_text, full_backtrace, full_command_string) VALUES (?,?,?,?,?,?,?);',(msg.id, msg.channel.id, ctx.command.name, str(type(error)), str(error), bt_string, ctx.message.content)) - - - @commands.Cog.listener() - async def on_raw_reaction_add(self, payload): if payload.user_id == self.bot.user.id: return From b5e6e40c7f1f15a4bf4c54bbfc54b360b54a3700 Mon Sep 17 00:00:00 2001 From: Jonathan Conlin Date: Tue, 19 Mar 2019 18:24:10 -0400 Subject: [PATCH 13/27] Cog inheritance and listener decorators (#35) * Added Cog inheritance and listeners * Added factorial support. * Cog inheritance and listener decorators * Factorial support * Fixed whitespace for cog inheritance and decorators * Fixed on_command_error listener. --- .gitignore | 1 + ALBot.py | 5 +++-- cogs/admin.py | 10 +++++----- cogs/compile.py | 9 +++++---- cogs/errors.py | 10 ++++++---- cogs/helloworld.py | 9 ++++----- cogs/help.py | 11 +++++------ cogs/memes.py | 19 +++++++++---------- cogs/messages.py | 4 ++-- cogs/music.py | 7 ++++--- cogs/projects.py | 5 ++--- cogs/reminder.py | 6 +++--- cogs/util.py | 4 ++-- cogs/welcome.py | 7 +++---- database/INFO.md | 6 +++--- 15 files changed, 57 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index bfd4ada..6ff139b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ __pycache__/ *.jpg config.py database/data/sqlite3.db + .idea/ diff --git a/ALBot.py b/ALBot.py index 4b9aec3..eb4817f 100644 --- a/ALBot.py +++ b/ALBot.py @@ -5,7 +5,7 @@ import cogs.CONSTANTS as CONSTANTS import config -'''Cogs to load when the bot first starts''' +"""Cogs to load when the bot first starts""" startup_cogs = [ "cogs.messages", "cogs.errors", @@ -41,4 +41,5 @@ async def on_ready(): exc = '{}: {}'.format(type(e).__name__, e) print('Failed to load extension {}\n{}'.format(extension, exc)) -bot.run(config.ALBOT_TOKEN) \ No newline at end of file + +bot.run(config.ALBOT_TOKEN) diff --git a/cogs/admin.py b/cogs/admin.py index fef47fc..3e55b97 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -7,7 +7,7 @@ import cogs.util -class Admin: +class Admin(commands.Cog, name='Admin'): def __init__(self, bot): self.bot = bot @@ -15,7 +15,7 @@ def __init__(self, bot): @commands.command(hidden=True) @commands.check(cogs.util.is_officer_check) async def load(self, ctx, extension_name : str): - '''Loads an extension.''' + """Loads an extension.""" try: if extension_name.startswith("cogs."): self.bot.load_extension(extension_name) @@ -39,7 +39,7 @@ async def unload(self, ctx, extension_name : str): @commands.command(hidden=True) @commands.check(cogs.util.is_officer_check) async def reload(self, ctx, extension_name : str): - '''Unloads and then loads an extension''' + """Unloads and then loads an extension""" try: if extension_name.startswith("cogs."): self.bot.unload_extension(extension_name) @@ -60,7 +60,7 @@ async def whereami(self, ctx): @commands.command(hidden=True, name="eval") @commands.check(cogs.util.is_owner) async def admin_eval(self, ctx, *, cmd : str): - '''Evaluates Python code only if the executor is hjarrell''' + """Evaluates Python code only if the executor is hjarrell""" env = { 'bot': self.bot, 'discord': discord, @@ -83,7 +83,7 @@ async def admin_eval(self, ctx, *, cmd : str): ret = await eval("__admin_eval()", env) except Exception as e: value = stdout.getvalue() - await ctx.send("```py\n{value}{e}\n```".format()) + await ctx.send("```py\n{}{}\n```".format(value, e)) else: value = stdout.getvalue() if ret is None: diff --git a/cogs/compile.py b/cogs/compile.py index 0bc50ff..f005eff 100644 --- a/cogs/compile.py +++ b/cogs/compile.py @@ -5,7 +5,8 @@ import cogs.util -class Compile: +class Compile(commands.Cog, name='Compile'): + def __init__(self, bot): self.bot = bot self.complangs = [] @@ -13,7 +14,7 @@ def __init__(self, bot): @commands.command(name="complangs") async def compile_langs(self, ctx): - '''Get the languages and ids for compiling code''' + """Get the languages and ids for compiling code""" if len(self.complangs) == 0: langs = requests.get("https://api.judge0.com/languages") @@ -27,7 +28,7 @@ async def compile_langs(self, ctx): @commands.command(name="compile") async def _compile(self, ctx, lang_id : int, *, program : str): - '''Compiles and runs code using the judge0 api''' + """Compiles and runs code using the judge0 api""" payload = {'source_code' : program, 'language_id' : lang_id} headers = {'Content-Type': "application/json"} r = requests.post("https://api.judge0.com/submissions/?base64_encoded=false&wait=true", data=json.dumps(payload), headers=headers) @@ -43,7 +44,7 @@ async def _compile(self, ctx, lang_id : int, *, program : str): @commands.command(name="compdebug") @commands.check(cogs.util.is_officer_check) async def debug_compile(self, ctx): - '''Toggles whether to print the full compile output''' + """Toggles whether to print the full compile output""" self.is_debug = not self.is_debug await ctx.send("is_debugging = {}".format(self.is_debug)) diff --git a/cogs/errors.py b/cogs/errors.py index 8967576..11e3b3b 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -9,9 +9,8 @@ from database.database import SQLCursor, SQLConnection from cogs.messages import track -class ALBotErrorHandlers: +class ALBotErrorHandlers(commands.Cog, name='Error Handler'): """ Handles errors """ - def __init__(self, bot, db): self.bot = bot self.db = db @@ -45,6 +44,7 @@ def _construct_unknown_command_embed(self, error_text, full_text): return embed + @commands.Cog.listener() async def on_command_error(self, ctx, error): if type(error) == discord.ext.commands.MissingPermissions: await ctx.message.add_reaction(CONSTANTS.REACTION_DENY) @@ -69,7 +69,8 @@ async def on_command_error(self, ctx, error): bt_string = ''.join(traceback.format_exception(type(error), error, error.__traceback__)) print('{bname} encountered an error:\n{0}'.format(bt_string, bname=CONSTANTS.BOT_NAME)) cur.execute('INSERT INTO error_messages (message_id, channel_id, command_name, error_name, error_text, full_backtrace, full_command_string) VALUES (?,?,?,?,?,?,?);',(msg.id, msg.channel.id, ctx.command.name, str(type(error)), str(error), bt_string, ctx.message.content)) - + + @commands.Cog.listener() async def on_raw_reaction_add(self, payload): if payload.user_id == self.bot.user.id: return @@ -84,7 +85,8 @@ async def on_raw_reaction_add(self, payload): to_edit = await self.bot.get_channel(payload.channel_id).get_message(payload.message_id) new_embed = self._construct_error_embed(row[0],row[1],row[2],row[3],row[4]) await to_edit.edit(content='{err} Command error {err}'.format(err=CONSTANTS.REACTION_ERROR),embed=new_embed) - + + @commands.Cog.listener() async def on_raw_reaction_remove(self, payload): if payload.user_id == self.bot.user.id: return diff --git a/cogs/helloworld.py b/cogs/helloworld.py index a6e2016..95f44cb 100644 --- a/cogs/helloworld.py +++ b/cogs/helloworld.py @@ -2,15 +2,14 @@ from discord.ext import commands import os -class HelloWorld: - '''Discord.py Cog for printing the hello world code for different languages''' - +class HelloWorld(commands.Cog, name='Hello World'): + """Discord.py Cog for printing the hello world code for different languages""" def __init__(self, bot): self.bot = bot @commands.command() async def hello(self, ctx, lang : str): - '''Prints the hello world source for any language defined in cogs/helloworld''' + """Prints the hello world source for any language defined in cogs/helloworld""" for fName in os.listdir("cogs/helloworld"): if fName == (lang.lower() + ".txt"): with open("cogs/helloworld/{}".format(fName), 'r') as f: @@ -18,7 +17,7 @@ async def hello(self, ctx, lang : str): @commands.command() async def hellolangs(self, ctx): - '''Prints all the languages that there are helloworld's for''' + """Prints all the languages that there are helloworld's for""" langs = '' for fName in os.listdir("cogs/helloworld"): langs += fName.replace('.txt','') + '\n' diff --git a/cogs/help.py b/cogs/help.py index bdb6993..4c0ff51 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -2,19 +2,18 @@ import random from discord.ext import commands -class Help: - '''Commands related to help needed''' +class Help(commands.Cog, name='Help'): + """Commands related to help needed""" def __init__(self, bot): self.bot = bot - @commands.command() async def question(self, ctx, *, q : str = ""): - ''' Forward a question to the officer chat + """ Forward a question to the officer chat Formats: !question !question [question to be answered] - ''' + """ member_name = ctx.message.author.name channel = self.bot.get_channel(436916990238785556) await channel.send("@everyone\n @"+member_name+" has a question!") @@ -23,4 +22,4 @@ async def question(self, ctx, *, q : str = ""): def setup(bot): - bot.add_cog(Help(bot)) \ No newline at end of file + bot.add_cog(Help(bot)) diff --git a/cogs/memes.py b/cogs/memes.py index 18834da..e65b601 100644 --- a/cogs/memes.py +++ b/cogs/memes.py @@ -4,9 +4,8 @@ import cogs.util -class Memes: - '''All meme related commands''' - +class Memes(commands.Cog, name='Memes'): + """All meme related commands""" def __init__(self, bot): self.bot = bot self.playing_strings = [] @@ -15,24 +14,24 @@ def __init__(self, bot): @commands.command() async def orange(self, ctx): - '''Responds to the classic football chant "Orange" "Blue"''' + """Responds to the classic football chant "Orange" "Blue""" await ctx.send("BLUE!") @commands.command() async def blue(self, ctx): - '''Responds to the classic football chant "Orange" "Blue"''' + """Responds to the classic football chant "Orange" "Blue""" await ctx.send("ORANGE!") @commands.command() async def about(self, ctx): - '''Prints information about the bots.''' + """Prints information about the bots.""" await ctx.send("We are your benevolent dictators. Fear us.") await ctx.send(file=discord.File('alligator.jpg')) @commands.command() @commands.check(cogs.util.is_officer_check) async def randplaying(self, ctx): - '''Randomly changes the playing text''' + """Randomly changes the playing text""" new_playing = random.choice(self.playing_strings) await self.bot.change_presence(activity=discord.Game(name=new_playing)) await ctx.send('I am now {}'.format(new_playing)) @@ -40,16 +39,16 @@ async def randplaying(self, ctx): @commands.command() @commands.check(cogs.util.is_officer_check) async def setplaying(self, ctx, *, playing: str): - '''Lets an officer set the playing text''' + """Lets an officer set the playing text""" await self.bot.change_presence(activity=discord.Game(name=playing)) @commands.command() async def say(self, ctx, *, phrase : str): - '''Has the bot say something''' + """Has the bot say something""" await ctx.send(phrase) async def on_guild_channel_create(self, channel): - '''Messages "First" when a channel is created''' + """Messages "First" when a channel is created""" await channel.send('First') def setup(bot): diff --git a/cogs/messages.py b/cogs/messages.py index c1360e8..abe6677 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -4,12 +4,13 @@ import cogs.CONSTANTS as CONSTANTS from database.database import SQLCursor, SQLConnection -class ALBotMessageDeletionHandlers: +class ALBotMessageDeletionHandlers(commands.Cog, name='Message Deletion Handlers'): """ Functions for handling tracked messages """ def __init__(self, bot, db): self.bot = bot self.db = db + @commands.Cog.listener() async def on_raw_reaction_add(self, payload): """ Checks reactions and deletes tracked messages when necessary. """ if payload.user_id == self.bot.user.id: @@ -43,6 +44,5 @@ async def track(message, author=None): with SQLCursor(sql_db) as cur: cur.execute("INSERT INTO tracked_messages (messid, sender_uid, track_time) VALUES (?, ?, ?);", (message.id, aid, message.created_at)) - def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) diff --git a/cogs/music.py b/cogs/music.py index fe98694..f7a7133 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -10,7 +10,8 @@ import youtube_dl class VoiceEntry: - '''A class that represents a song that can be played''' + + """A class that represents a song that can be played""" def __init__(self, message, player, title, uploader, duration): self.requester = message.author self.channel = message.channel @@ -26,7 +27,7 @@ def __str__(self): return fmt.format(self.title, self.uploader, self.requester) class VoiceState: - '''Holds the queued song and players for a guild server''' + """Holds the queued song and players for a guild server""" def __init__(self, bot): self.current = None self.voice = None @@ -65,7 +66,7 @@ async def audio_player_task(self): self.voice.play(self.current.player) await self.play_next_song.wait() -class Music: +class Music(commands.Cog, name='Music'): """Voice related commands. Works in multiple servers at once. """ diff --git a/cogs/projects.py b/cogs/projects.py index 008297d..31388f2 100644 --- a/cogs/projects.py +++ b/cogs/projects.py @@ -2,9 +2,8 @@ from discord.utils import get from discord.ext import commands -class Projects: - '''Commands dealing with the different projects we are working on''' - +class Projects(commands.Cog, name='Projects'): + """Commands dealing with the different projects we are working on""" def __init__(self, bot): self.bot = bot diff --git a/cogs/reminder.py b/cogs/reminder.py index db8327a..e50c169 100644 --- a/cogs/reminder.py +++ b/cogs/reminder.py @@ -4,8 +4,8 @@ import asyncio from discord.ext import commands -class Reminder: - '''To remind officers and members about things''' +class Reminder(commands.Cog, name='Reminder'): + """To remind officers and members about things""" def __init__(self, bot): self.bot = bot self.book_room_bg_task = self.bot.loop.create_task(self.book_room_reminder()) @@ -29,4 +29,4 @@ async def book_room_reminder(self): await asyncio.sleep(60) # check every 1 minute def setup(bot): - bot.add_cog(Reminder(bot)) \ No newline at end of file + bot.add_cog(Reminder(bot)) diff --git a/cogs/util.py b/cogs/util.py index 15d2068..d30e79a 100644 --- a/cogs/util.py +++ b/cogs/util.py @@ -1,9 +1,9 @@ import discord def is_officer_check(ctx): - '''Check to see if the author is an officer''' + """Check to see if the author is an officer""" return discord.utils.get(ctx.message.author.roles, name='officer') is not None def is_owner(ctx): - '''Check to see if the author is an hjarrell''' + """Check to see if the author is an hjarrell""" return ctx.message.author.id == 402565484072927235 diff --git a/cogs/welcome.py b/cogs/welcome.py index 1f81669..f1896c6 100644 --- a/cogs/welcome.py +++ b/cogs/welcome.py @@ -3,14 +3,13 @@ from discord.ext import commands import config -class Welcome: - '''To automatically welcome new members to the server''' - +class Welcome(commands.Cog, name="Welcome"): + """To automatically welcome new members to the server""" def __init__(self, bot): self.bot = bot async def on_member_join(self, member): - fmt = '''Welcome {0.mention}! \nFeel free to use \"!question\" to let us know if you have any questions \nAnd you can also use \"!help\", all in the #bot-spam channel to find out about what you can do with our Discord bot ALBot :D ''' + fmt = """Welcome {0.mention}! \nFeel free to use \"!question\" to let us know if you have any questions \nAnd you can also use \"!help\", all in the #bot-spam channel to find out about what you can do with our Discord bot ALBot :D """ dm_channel = member.dm_channel if dm_channel == None: await member.create_dm() diff --git a/database/INFO.md b/database/INFO.md index 5befa74..0c8b9cc 100644 --- a/database/INFO.md +++ b/database/INFO.md @@ -12,7 +12,7 @@ from sql.sql import SQLConnection, SQLCursor, SQLRollback connection = SQLConnection() # Checks the database integrity and returns a new connection object with SQLCursor(connection) as cursor: # The backend uses a context manager to wrap the cursor object - ''' Get data from some_table ''' + """ Get data from some_table """ cursor.execute('SELECT * FROM some_table;') result = cursor.fetchall() @@ -24,7 +24,7 @@ with SQLCursor(connection) as cursor: # The backend uses a context manager to wr some_message_id = 484572171608522771 some_message_text = 'The Spanish Inquisition' with SQLCursor(connection) as cursor: - ''' Insert values into some_table, sanitizing them to prevent naughty business. ''' + """ Insert values into some_table, sanitizing them to prevent naughty business. """ cursor.execute('INSERT INTO some_table (message_id, message_text) VALUES (?,?);', (some_message_id, some_message_text)) print('done') # Changes are automatically committed at the end of the 'with' statement. @@ -37,7 +37,7 @@ some_message_text = 'My most embarassing secrets that I would never want in an S message_is_regretted = True with SQLCursor(connection) as cursor: - ''' Insert a value, then roll it back ''' + """ Insert a value, then roll it back """ cursor.execute('INSERT INTO some_table (message_id, message_text) VALUES (?, ?);', (some_message_id, some_message_text)) if message_is_regretted: From a5d8ce0beea942cf34d9d97821161ac3ff38bec5 Mon Sep 17 00:00:00 2001 From: Jonathan Conlin Date: Tue, 19 Mar 2019 18:30:08 -0400 Subject: [PATCH 14/27] Factorial support (#34) * Added Cog inheritance and listeners * Added factorial support. * Cog inheritance and listener decorators * Factorial support * Fixed whitespace issue on decorator --- .gitignore | 1 + ALBot.py | 1 - cogs/memes.py | 1 + cogs/messages.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6ff139b..3353b1a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ __pycache__/ config.py database/data/sqlite3.db + .idea/ diff --git a/ALBot.py b/ALBot.py index eb4817f..9b3ee84 100644 --- a/ALBot.py +++ b/ALBot.py @@ -40,6 +40,5 @@ async def on_ready(): except Exception as e: exc = '{}: {}'.format(type(e).__name__, e) print('Failed to load extension {}\n{}'.format(extension, exc)) - bot.run(config.ALBOT_TOKEN) diff --git a/cogs/memes.py b/cogs/memes.py index e65b601..8b6a069 100644 --- a/cogs/memes.py +++ b/cogs/memes.py @@ -51,5 +51,6 @@ async def on_guild_channel_create(self, channel): """Messages "First" when a channel is created""" await channel.send('First') + def setup(bot): bot.add_cog(Memes(bot)) diff --git a/cogs/messages.py b/cogs/messages.py index abe6677..ff936f4 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -44,5 +44,36 @@ async def track(message, author=None): with SQLCursor(sql_db) as cur: cur.execute("INSERT INTO tracked_messages (messid, sender_uid, track_time) VALUES (?, ?, ?);", (message.id, aid, message.created_at)) +class ALBotFactorialHandler(commands.Cog, name='Factorial Handler'): + + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_message(self, msg): + """Checks message for factorial format using regex.""" + if msg.author != self.bot.user: + import re + filtered_msg = re.findall('{(?:[0-9]|[1-8](?:[0-9]{1,2})?)!}', msg.content) + if filtered_msg is not None: + group_len = len(filtered_msg) + factorial = 'Factorial: `{}! = {}`' if group_len == 1 else 'The following factorials were calculated as:```' + import math + if group_len > 1: + for i in range(0, group_len): + num = int((filtered_msg[i].split('!')[0])[1:]) + product = math.factorial(num) + factorial += '\n\n{}! = {}'.format(num, product) + await msg.channel.send(factorial + '```') + elif group_len == 1: + try: + num = int((filtered_msg[0].split('!')[0])[1:]) + await msg.channel.send(factorial.format(num, math.factorial(num))) + except discord.HTTPException as e: + await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') + + await self.bot.process_commands(msg) + def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) + bot.add_cog(ALBotFactorialHandler(bot)) From 423697b9375d2328d80c60c0b140e447b13fbf90 Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Tue, 19 Mar 2019 18:56:48 -0400 Subject: [PATCH 15/27] Update the code to the latest rewrite commit. The API we use Discord.py made some breaking changes. The exceptions for cogs changed, and the listener for all messages. --- cogs/admin.py | 10 ++++------ cogs/errors.py | 12 ++++++------ cogs/messages.py | 6 ++---- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/cogs/admin.py b/cogs/admin.py index 3e55b97..b32dd17 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -21,7 +21,7 @@ async def load(self, ctx, extension_name : str): self.bot.load_extension(extension_name) else: self.bot.load_extension("cogs." + extension_name) - except (AttributeError, ImportError) as e: + except Exception as e: await ctx.send("```py\n{}: {}\n```".format(type(e).__name__, str(e))) return await ctx.send("{} loaded.".format(extension_name)) @@ -42,12 +42,10 @@ async def reload(self, ctx, extension_name : str): """Unloads and then loads an extension""" try: if extension_name.startswith("cogs."): - self.bot.unload_extension(extension_name) - self.bot.load_extension(extension_name) + self.bot.reload_extension(extension_name) else: - self.bot.unload_extension("cogs." + extension_name) - self.bot.load_extension("cogs." + extension_name) - except (AttributeError, ImportError) as e: + self.bot.reload_extension("cogs." + extension_name) + except Exception as e: await ctx.send("```py\n{}: {}\n```".format(type(e).__name__, str(e))) return await ctx.send("{} reloaded.".format(extension_name)) diff --git a/cogs/errors.py b/cogs/errors.py index 11e3b3b..1bc9332 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -33,9 +33,9 @@ def _construct_error_embed(self, command_name, error_name, error_text, full_comm break else: embed.add_field(name='Press {expand}'.format(expand=CONSTANTS.REACTION_EXPAND), value='for full error backtrace', inline=False) - + return embed - + def _construct_unknown_command_embed(self, error_text, full_text): title = "{notfound} Invalid command.".format(notfound=CONSTANTS.REACTION_NOT_FOUND) embed = discord.Embed(title=title, colour=discord.Colour(CONSTANTS.EMBED_COLOR_ERROR), description='```{0}```'.format(error_text)) @@ -82,7 +82,7 @@ async def on_raw_reaction_add(self, payload): if not row: return - to_edit = await self.bot.get_channel(payload.channel_id).get_message(payload.message_id) + to_edit = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) new_embed = self._construct_error_embed(row[0],row[1],row[2],row[3],row[4]) await to_edit.edit(content='{err} Command error {err}'.format(err=CONSTANTS.REACTION_ERROR),embed=new_embed) @@ -98,11 +98,11 @@ async def on_raw_reaction_remove(self, payload): if not row: return - to_edit = await self.bot.get_channel(payload.channel_id).get_message(payload.message_id) + to_edit = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) new_embed = self._construct_error_embed(row[0],row[1],row[2],row[3]) await to_edit.edit(content='{err} Command error {err}'.format(err=CONSTANTS.REACTION_ERROR),embed=new_embed) - - + + def setup(bot): bot.add_cog(ALBotErrorHandlers(bot, SQLConnection())) diff --git a/cogs/messages.py b/cogs/messages.py index ff936f4..a2e211b 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -24,12 +24,12 @@ async def on_raw_reaction_add(self, payload): if row: is_tracked = True sender_uid = row[1] - + if is_tracked: reacting_member = self.bot.get_guild(payload.guild_id).get_member(payload.user_id) can_delete = self.bot.get_channel(payload.channel_id).permissions_for(reacting_member).manage_messages if payload.user_id == sender_uid or can_delete: - relevant_message = await self.bot.get_channel(payload.channel_id).get_message(payload.message_id) + relevant_message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) await relevant_message.delete() async def track(message, author=None): @@ -72,8 +72,6 @@ async def on_message(self, msg): except discord.HTTPException as e: await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') - await self.bot.process_commands(msg) - def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) bot.add_cog(ALBotFactorialHandler(bot)) From 9383436a0b218dabc204be39e5d9c4c3b0c34c42 Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Tue, 19 Mar 2019 19:00:40 -0400 Subject: [PATCH 16/27] Disable compile cog. Disable the compile cog while it crashes the bot. --- ALBot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ALBot.py b/ALBot.py index 9b3ee84..405cf07 100644 --- a/ALBot.py +++ b/ALBot.py @@ -14,7 +14,6 @@ "cogs.projects", "cogs.admin", "cogs.music", - "cogs.compile", "cogs.welcome", "cogs.help", "cogs.reminder" @@ -32,7 +31,8 @@ async def on_ready(): print('Invite URL: {iurl}'.format(iurl=bot_url.format(bot.user.id))) print('-----') await bot.change_presence(activity=discord.Game(name="Destroying propritary software")) - + + if __name__ == "__main__": for extension in startup_cogs: try: From 297e1403a8d909bef18e9b8590c6d508c416834f Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Tue, 9 Apr 2019 18:31:53 -0400 Subject: [PATCH 17/27] Update requirements to use newest release of Discord.py --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 97a5616..927b6ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -git+https://github.com/Rapptz/discord.py@rewrite#egg=discord.py[voice] +discord.py[voice] youtube_dl requests From 22706e522296375dfb005865b96eb8c1f7c7a06a Mon Sep 17 00:00:00 2001 From: Jon Date: Sun, 21 Apr 2019 15:50:06 -0400 Subject: [PATCH 18/27] Merge 'develop' into forked-branch 'develop'. --- ALBot.py | 4 +--- cogs/government.py | 43 +++++++++++++++++++++++++++++++++++++++++++ cogs/messages.py | 7 ------- database/schema.json | 17 +++++++++++++++++ 4 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 cogs/government.py diff --git a/ALBot.py b/ALBot.py index c1a1fce..3db3f50 100644 --- a/ALBot.py +++ b/ALBot.py @@ -14,9 +14,7 @@ "cogs.projects", "cogs.admin", "cogs.music", - "cogs.welcome", - "cogs.help", - "cogs.reminder" + "cogs.government" ] bot_url = 'https://discordapp.com/api/oauth2/authorize?client_id={0}&scope=bot&permissions=0' diff --git a/cogs/government.py b/cogs/government.py new file mode 100644 index 0000000..71922f4 --- /dev/null +++ b/cogs/government.py @@ -0,0 +1,43 @@ +from discord.ext import commands +from database.database import SQLCursor, SQLConnection + + +class Government(commands.Cog, name='Government'): + """Handles all of the UFOSC government related commands and querying.""" + def __init__(self, bot, db): + self.bot = bot + self.db = db + + # Valid positions types. TODO: Consider changing to an enum type. + positions = ['social_chair', 'external_relations', 'secretary', 'server_admin'] + + @commands.group(invoke_without_command=True, name='govt') + # means that it will run this code if you just do "!example" + async def government(self, ctx): + await ctx.send("works!") + + @government.command() + async def list(self, ctx): + """The list subcommand displays the government positions and their corresponding descriptions.""" + positions = await self.query_positions() + msg = '' + for position in positions: + if position[0] is not (None or ''): + msg += position['position'] + ' - ' + position['officer'] + if msg is not '': + ctx.send(msg) + + async def query_positions(self): + """Returns an array of positions and corresponding descriptions.""" + positions = [] + counter = 0 + with SQLCursor(self.db) as cur: + for pos in self.positions: + cur.execute('SELECT position, description, officer FROM govt_info WHERE position=?', pos) + row = cur.fetchone() + if row: + positions[counter] = {'position': row[0] if row[0] is not None else 'NULL', 'description': row[1] if row[1] is not None else '', 'officer': row[2] if row[2] is not None else 'Vacant'} + else: + positions[counter] = {} + counter += 1 + return positions diff --git a/cogs/messages.py b/cogs/messages.py index ef43726..d4ce25d 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -71,12 +71,5 @@ async def on_message(self, msg): await msg.channel.send(factorial.format(num, math.factorial(num))) except discord.HTTPException as e: await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') -<<<<<<< HEAD - - await self.bot.process_commands(msg) -======= ->>>>>>> 297e1403a8d909bef18e9b8590c6d508c416834f - def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) - bot.add_cog(ALBotFactorialHandler(bot)) diff --git a/database/schema.json b/database/schema.json index be2870f..a903615 100644 --- a/database/schema.json +++ b/database/schema.json @@ -48,5 +48,22 @@ "type" : "TEXT" } ] + }, + { + "table_name" : "govt_info", + "schema" : [ + { + "column_name" : "position", + "type" : "TEXT" + }, + { + "column_name" : "description", + "type" : "TEXT" + }, + { + "column_name" : "officer", + "type" : "TEXT" + } + ] } ] From 403ac0d34bf21747250a281ced9b611fc2cd618a Mon Sep 17 00:00:00 2001 From: Logan Smith Date: Wed, 24 Apr 2019 21:09:00 -0400 Subject: [PATCH 19/27] Added a basic toggle for stealing the top post on /r/programmerhumor --- .gitignore | 2 +- cogs/memes.py | 32 ++++++++++++++++++++++++++++++++ requirements.txt | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3353b1a..9e5e39c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,6 @@ __pycache__/ *.jpg config.py database/data/sqlite3.db - +praw.ini .idea/ diff --git a/cogs/memes.py b/cogs/memes.py index 8b6a069..30257d2 100644 --- a/cogs/memes.py +++ b/cogs/memes.py @@ -1,5 +1,7 @@ +import asyncio import discord import random +import praw from discord.ext import commands import cogs.util @@ -8,6 +10,7 @@ class Memes(commands.Cog, name='Memes'): """All meme related commands""" def __init__(self, bot): self.bot = bot + self.going_for_gold = False self.playing_strings = [] with open('cogs/playing_strings.txt', 'r') as f: self.playing_strings = f.read().splitlines() @@ -51,6 +54,35 @@ async def on_guild_channel_create(self, channel): """Messages "First" when a channel is created""" await channel.send('First') + @commands.command() + async def getkarma(self, ctx): + """Makes the bot hungry for karma""" + await ctx.send("You are enabling daily karma grabbing from /r/programmerhumor") + self.going_for_gold = True + await self.dailykarma() + + @commands.command() + async def forgetkarma(self, ctx): + """What's Reddit?""" + await ctx.send("You are disabling daily karma grabbing from /r/programmerhumor") + self.going_for_gold = False + + async def dailykarma(self): + """Steals the top Reddit post for the day from /r/ph""" + channel = self.bot.get_channel(436915955348537346) + while self.going_for_gold: + reddit = praw.Reddit('bot1') + for submission in reddit.subreddit('programmerhumor').hot(limit=5): + picture_url = submission.url + ending = picture_url[-4:] + if ending == ".jpg": + comments = list(submission.comments) + mycomment = comments[0] + await channel.send(mycomment.body) + break + await channel.send("I made this, give me karma") + await channel.send(picture_url) + await asyncio.sleep(86400) def setup(bot): bot.add_cog(Memes(bot)) diff --git a/requirements.txt b/requirements.txt index 927b6ed..c7b2202 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ discord.py[voice] youtube_dl requests +praw From 9c62efeb5e0562c384cafed81dc92c7253b0d0e1 Mon Sep 17 00:00:00 2001 From: Logan Smith Date: Sun, 28 Apr 2019 21:16:19 -0400 Subject: [PATCH 20/27] Added the code to handle assigning an alumnus role --- cogs/projects.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cogs/projects.py b/cogs/projects.py index 31388f2..fecdbee 100644 --- a/cogs/projects.py +++ b/cogs/projects.py @@ -7,6 +7,13 @@ class Projects(commands.Cog, name='Projects'): def __init__(self, bot): self.bot = bot + async def alumnus(self, ctx): + """"Add the Alumnus role to the user""" + role = discord.utils.get(ctx.guild.roles, name="alumnus") + await ctx.author.add_roles(role) + await ctx.send("Eway elcomway youway otay hetay alumni ounglay") + await ctx.send(":thinking:") + async def muddy(self, ctx): """Add the muddy swamp role to the user""" role = discord.utils.get(ctx.guild.roles, name="muddy-swamp") @@ -29,7 +36,9 @@ async def mvw(self, ctx): @commands.command() async def join(self, ctx, *, roleName: str): """Add a role to a user""" - if roleName.lower() in ["muddy", "muddy swamp", "muddyswamp", "muddy-swamp", "MUD"]: + if roleName.lower() in ["alumni", "alumnus", "alumna", "alum", "stultus", "stulta"]: + await self.alumnus(ctx) + elif roleName.lower() in ["muddy", "muddy swamp", "muddyswamp", "muddy-swamp", "MUD"]: await self.muddy(ctx) elif roleName.lower() in ["website", "club site", "club website", "clubwebsite", "clubsite"]: await self.website(ctx) From 605530c1f7dc0cfd86225e98a7f5c90e1c450115 Mon Sep 17 00:00:00 2001 From: Dakota Rennemann Date: Wed, 8 May 2019 23:24:23 -0400 Subject: [PATCH 21/27] Clear command removes messages The clear command now removes the last x amount of messages if the message is not pinned and the person using the command has manage_channel permissions --- cogs/messages.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cogs/messages.py b/cogs/messages.py index a2e211b..8bc9622 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -72,6 +72,24 @@ async def on_message(self, msg): except discord.HTTPException as e: await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') + +class ALBotMessageClear(commands.Cog, name='Message Clear'): + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def clear(self, ctx, a_number: int): + + can_delete = self.bot.get_channel(ctx.channel.id).permissions_for(ctx.author).manage_messages + print(can_delete) + if can_delete: + async for message in ctx.channel.history(limit=a_number+1): + if not message.pinned: + relevant_message = await self.bot.get_channel(ctx.channel.id).fetch_message(message.id) + await relevant_message.delete() + + def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) bot.add_cog(ALBotFactorialHandler(bot)) + bot.add_cog(ALBotMessageClear(bot)) From 0854f262322c6f7a39daf1f66e43361e575fb4ff Mon Sep 17 00:00:00 2001 From: Dakota Rennemann Date: Thu, 9 May 2019 02:42:04 -0400 Subject: [PATCH 22/27] WIP - Implement emoji reply on 50+ warning --- cogs/messages.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/cogs/messages.py b/cogs/messages.py index 8bc9622..539cfb4 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -1,6 +1,8 @@ import discord from discord.ext import commands +import asyncio + import cogs.CONSTANTS as CONSTANTS from database.database import SQLCursor, SQLConnection @@ -74,20 +76,37 @@ async def on_message(self, msg): class ALBotMessageClear(commands.Cog, name='Message Clear'): + """Functions for handling message deletion in channels""" def __init__(self, bot): self.bot = bot @commands.command() - async def clear(self, ctx, a_number: int): + async def clear(self, ctx, a_number=0): + # Checks if number is positive int + if not a_number > 0: + await ctx.channel.send(content="Please input a number larger than zero") + return can_delete = self.bot.get_channel(ctx.channel.id).permissions_for(ctx.author).manage_messages - print(can_delete) if can_delete: - async for message in ctx.channel.history(limit=a_number+1): + buffer = 1 + # Warns user if the number is greater than 50 + if a_number > 50: + buffer += 1 + await ctx.channel.send( + content="WARNING: You are about to delete more than 50 messages, are you sure you want to do this?") + reactions = ["✅", "❌"] + for emoji in reactions: + await ctx.channel.last_message.add_reaction(emoji) + await ctx.channel.send( + content="Insert emoji reaction effects here, temporary 10 second wait time until implememnted") + await asyncio.sleep(10) + + async for message in ctx.channel.history(limit=a_number+buffer): if not message.pinned: relevant_message = await self.bot.get_channel(ctx.channel.id).fetch_message(message.id) await relevant_message.delete() - + await ctx.channel.send(content='@{} Successfully deleted {} messages'.format(ctx.author, a_number)) def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) From 823c8be8db2f8b26866c92de16a33c96fc3cb8ab Mon Sep 17 00:00:00 2001 From: Jonathan Conlin Date: Thu, 9 May 2019 14:29:47 -0400 Subject: [PATCH 23/27] Government features/commands. Non-final. --- cogs/government.py | 174 +++++++++++++++++++++++++++++++++++++++---- cogs/messages.py | 1 + database/schema.json | 1 + 3 files changed, 161 insertions(+), 15 deletions(-) diff --git a/cogs/government.py b/cogs/government.py index 71922f4..8fe2c80 100644 --- a/cogs/government.py +++ b/cogs/government.py @@ -1,9 +1,13 @@ +import discord +import typing from discord.ext import commands -from database.database import SQLCursor, SQLConnection +from database.database import SQLCursor, SQLConnection +# TODO: store Officer objects locally during bot lifespan to avoid excess database querying class Government(commands.Cog, name='Government'): """Handles all of the UFOSC government related commands and querying.""" + def __init__(self, bot, db): self.bot = bot self.db = db @@ -11,33 +15,173 @@ def __init__(self, bot, db): # Valid positions types. TODO: Consider changing to an enum type. positions = ['social_chair', 'external_relations', 'secretary', 'server_admin'] - @commands.group(invoke_without_command=True, name='govt') - # means that it will run this code if you just do "!example" + @commands.group(invoke_without_command=True, name='eboard') + @commands.guild_only() async def government(self, ctx): - await ctx.send("works!") + """The root command for managing and checking government/officer information.""" + await ctx.message.channel.send( + 'List of useable commands for the parent command: **eboard**\n\n**eboard seats** - shows a list of all government positions and their corresponding officers.\n\n**eboard position \"\"** - shows the current officer that fills this position and a description of the position.') - @government.command() - async def list(self, ctx): - """The list subcommand displays the government positions and their corresponding descriptions.""" + @government.group(invoke_without_command=True) + @commands.guild_only() + async def seats(self, ctx): + """The seats subcommand displays the government positions and their corresponding descriptions.""" positions = await self.query_positions() msg = '' for position in positions: - if position[0] is not (None or ''): - msg += position['position'] + ' - ' + position['officer'] + msg += position['position'].replace('_', " ").capitalize() + ' - ' + try: + if ',' in position['officer']: + officers = [str(ctx.message.guild.get_member(int(member_id))) for member_id in position['officer'].split(',')] + msg += ', '.join(officers) + '\n' + else: + msg += (str(ctx.message.guild.get_member(int(position['officer']))) if position['officer'] is not None and position['officer'].strip() is not 'Vacant' else 'Vacant') + '\n' + except KeyError as e: + msg += 'Vacant\n' if msg is not '': - ctx.send(msg) + await ctx.send(msg) + + @government.group(invoke_without_command=True) + @commands.guild_only() + async def admin(self, ctx): + """The admin root command meant to handle all admin subcommands.""" + if ctx.message.author.top_role.name.lower() == 'officer': + await ctx.message.channel.send('List of useable commands for the parent command: **admin**\n\n **eboard admin auto** - updates the new seats given current election data.\n\n**eboard admin set ** - assigns a position to target user.\n\n**eboard admin remove ** - remove a target user from their position.\n\n**eboard admin list** - lists the positions in the SQLite table.') + + @government.group(name='position') + @commands.guild_only() + async def show_occupants(self, ctx, position=''): + pos = position.title() + position = position.replace(' ', '_') + if position.lower() in self.positions: + with SQLCursor(self.db) as cur: + cur.execute('SELECT description, officer FROM govt_info WHERE position = ?;', (position,)) + row = cur.fetchone() + if row: + plural = False + if row[1] is not None and ',' in row[1]: + officers = [str(ctx.message.guild.get_member(int(member_id))) for member_id in row[1].split(',')] + officers = ', '.join(officers) + plural = True + else: + officers = (str(ctx.message.guild.get_member(int(row[1]))) if row[1] is not None and row[1].strip() is not '' else 'Vacant') + description = row[0] + await ctx.message.channel.send('The current _{}_: _{}_'.format(pos + ('s are' if plural else ' is'), officers)) + if description is not None and description.strip() is not '': + await ctx.message.channel.send('Description: {}'.format(description)) + else: + await ctx.channel.send('Invalid position. Here is a list of valid positions: ' + ', '.join(self.positions).replace('_', ' ')) + + @admin.group() + @commands.guild_only() + async def list(self, ctx): + if ctx.message.author.top_role.name.lower() == 'officer': + await ctx.message.channel.send('The list of positions in the SQLite table: ' + ', '.join(self.positions)) + else: + await ctx.message.channel.send('Hey! You do not have permission to do that.') + + @admin.group() + @commands.guild_only() + async def clear(self, ctx): + """Clears all officers from their positions in the SQLite table.""" + if ctx.message.author.top_role.name.lower() == 'officer': + with SQLCursor(self.db) as cur: + cur.execute('UPDATE govt_info SET officer = Null;') + await ctx.message.channel.send('Successfully cleared all officers from all positions in the SQLite table.') + else: + await ctx.message.channel.send('Hey! You do not have permission to do that.') + + @admin.group() + @commands.guild_only() + async def auto(self, ctx): + """Automatically update roles and officer positions based on election results.""" + if ctx.message.author.top_role.name.lower() == 'officer': + await ctx.message.channel.send('Still working on integration with the election results. Maybe have a command to link to an elections database?') + else: + await ctx.message.channel.send('Hey! You do not have permission to do that.') + + @admin.group() + @commands.guild_only() + async def set(self, ctx, position, user: discord.User): + if ctx.message.author.top_role.name.lower() == 'officer': + member_id = user.id + if position is None or member_id is None: + await ctx.message.channel.send('Invalid command format, try: `eboard admin set <@User#0000>`') + else: + with SQLCursor(self.db) as cur: + cur.execute('SELECT officer FROM govt_info WHERE position = ?;', (position,)) + row = cur.fetchone() + if row: + officers = ','.join(row) if row[0] is not None else '' + if str(member_id) in officers: + return + officers += (',' if officers.strip() is not '' else '') + '{0}'.format(str(member_id)) + else: + officers = str(member_id) + + cur.execute('UPDATE govt_info SET officer = ? WHERE position = ?;', (officers, position)) + await ctx.message.channel.send('Successfully added **{}** to the **{}** position.'.format(str(user), position)) + else: + await ctx.message.channel.send('Hey! You do not have permission to do that.') + + @admin.group() + @commands.guild_only() + async def remove(self, ctx, position, user: discord.User): + member_id = user.id + if ctx.message.author.top_role.name.lower() == 'officer': + with SQLCursor(self.db) as cur: + cur.execute('SELECT officer FROM govt_info WHERE position = ?;', (position,)) + row = cur.fetchone() + if row: + officers = ','.join(row) if row[0] is not None else '' + if officers.strip() != '': + officers = officers.replace(str(member_id) + ',', '').replace(str(member_id), '') + if len(officers.split(',')) == 1: + officers = officers.replace(',', '') + elif officers[len(officers) - 1:len(officers)] == ',': + officers = officers[0:len(officers) - 1] + cur.execute('UPDATE govt_info SET officer = ? WHERE position = ?;', (officers, position)) + await ctx.message.channel.send('Successfully removed **{}** from the **{}** position.'.format(str(user), position)) + else: + await ctx.message.channel.send('Hey! You do not have permission to do that.') + + async def query_position(self, position): + """Return all of the officers for a corresponding position as a string list separated by commas.""" + with SQLCursor(self.db) as cur: + cur.execute('SELECT officer FROM govt_info WHERE position=?', (position,)) + row = cur.fetchone() + if row: + return row[0] if not None else '' async def query_positions(self): """Returns an array of positions and corresponding descriptions.""" - positions = [] + values = [{} for _ in range(4)] counter = 0 with SQLCursor(self.db) as cur: for pos in self.positions: - cur.execute('SELECT position, description, officer FROM govt_info WHERE position=?', pos) + cur.execute('SELECT position, description, officer FROM govt_info WHERE position=?', (pos,)) row = cur.fetchone() if row: - positions[counter] = {'position': row[0] if row[0] is not None else 'NULL', 'description': row[1] if row[1] is not None else '', 'officer': row[2] if row[2] is not None else 'Vacant'} + values[counter] = {'position': row[0] if len(row) >= 1 else 'NULL', + 'description': row[1] if row[1] is not None else '', + 'officer': row[2] if row[2] is not None else 'Vacant'} else: - positions[counter] = {} + values[counter] = {} counter += 1 - return positions + return values + + +def initialize(): + """Initializes the table with non-null 'position' columns.""" + sql_db = SQLConnection() + with SQLCursor(sql_db) as cur: + cur.execute('SELECT position from govt_info') + row = cur.fetchone() + for pos in Government.positions: + if row is None or len(row) != len(Government.positions): + cur.execute('INSERT OR IGNORE INTO govt_info (position) VALUES (?);', (pos,)) + + +def setup(bot): + bot.add_cog(Government(bot, SQLConnection())) + initialize() diff --git a/cogs/messages.py b/cogs/messages.py index d4ce25d..e20695b 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -71,5 +71,6 @@ async def on_message(self, msg): await msg.channel.send(factorial.format(num, math.factorial(num))) except discord.HTTPException as e: await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') + def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) diff --git a/database/schema.json b/database/schema.json index a903615..5f2cfa7 100644 --- a/database/schema.json +++ b/database/schema.json @@ -54,6 +54,7 @@ "schema" : [ { "column_name" : "position", + "primary" : true, "type" : "TEXT" }, { From 8aefecd9b4d1bbed1010f5a38ac00bf08339d7f8 Mon Sep 17 00:00:00 2001 From: Jonathan Conlin Date: Tue, 21 May 2019 18:41:36 -0400 Subject: [PATCH 24/27] Government functions and support for managing officers and their descriptions. --- ALBot.py | 2 +- cogs/government.py | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ALBot.py b/ALBot.py index 3db3f50..42fc00d 100644 --- a/ALBot.py +++ b/ALBot.py @@ -19,7 +19,7 @@ bot_url = 'https://discordapp.com/api/oauth2/authorize?client_id={0}&scope=bot&permissions=0' -bot = commands.Bot(command_prefix="!", description="ALBot (A Lame Bot)", case_insensitive=True, command_not_found="Invalid command: {}") +bot = commands.Bot(command_prefix="?", description="ALBot (A Lame Bot)", case_insensitive=True, command_not_found="Invalid command: {}") @bot.event async def on_ready(): diff --git a/cogs/government.py b/cogs/government.py index 8fe2c80..f899ea7 100644 --- a/cogs/government.py +++ b/cogs/government.py @@ -66,9 +66,9 @@ async def show_occupants(self, ctx, position=''): else: officers = (str(ctx.message.guild.get_member(int(row[1]))) if row[1] is not None and row[1].strip() is not '' else 'Vacant') description = row[0] - await ctx.message.channel.send('The current _{}_: _{}_'.format(pos + ('s are' if plural else ' is'), officers)) + await ctx.message.channel.send('The current _{}: _{}_'.format(pos + ('s_ are' if plural else '_ is'), officers)) if description is not None and description.strip() is not '': - await ctx.message.channel.send('Description: {}'.format(description)) + await ctx.message.channel.send('Description: \n```{}```'.format(description)) else: await ctx.channel.send('Invalid position. Here is a list of valid positions: ' + ', '.join(self.positions).replace('_', ' ')) @@ -100,6 +100,22 @@ async def auto(self, ctx): else: await ctx.message.channel.send('Hey! You do not have permission to do that.') + @admin.group() + @commands.guild_only() + async def description(self, ctx, pos ='', desc=''): + if ctx.message.author.top_role.name.lower() == 'officer': + if pos.strip() is not '': + with SQLCursor(self.db) as cur: + cur.execute('UPDATE govt_info SET description = ? WHERE position = ?;', (desc, pos)) + if desc.strip() is '': + await ctx.message.channel.send('Successfully cleared the description for position: **{}**'.format(pos)) + else: + await ctx.message.channel.send('Successfully set a description for position: **{}**\n\nThe description is as follows:\n```{}```'.format(pos, desc)) + else: + await ctx.message.channel.send('Invalid format, try: **eboard admin description \"\"**') + else: + await ctx.message.channel.send('Hey! You do not have permission to do that.') + @admin.group() @commands.guild_only() async def set(self, ctx, position, user: discord.User): From f1d2c460ece1877e64754ef0778b1ce1fccbb586 Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Wed, 22 May 2019 19:21:05 -0400 Subject: [PATCH 25/27] Remove unfinished clear command Remove the clear command changes from this pull request since this hasn't been merged into develop yet. --- cogs/messages.py | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/cogs/messages.py b/cogs/messages.py index 539cfb4..a2e211b 100644 --- a/cogs/messages.py +++ b/cogs/messages.py @@ -1,8 +1,6 @@ import discord from discord.ext import commands -import asyncio - import cogs.CONSTANTS as CONSTANTS from database.database import SQLCursor, SQLConnection @@ -74,41 +72,6 @@ async def on_message(self, msg): except discord.HTTPException as e: await msg.channel.send('Cannot post answer due to excessive character count! Maximum factorial allowed is `801!`.') - -class ALBotMessageClear(commands.Cog, name='Message Clear'): - """Functions for handling message deletion in channels""" - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def clear(self, ctx, a_number=0): - # Checks if number is positive int - if not a_number > 0: - await ctx.channel.send(content="Please input a number larger than zero") - return - - can_delete = self.bot.get_channel(ctx.channel.id).permissions_for(ctx.author).manage_messages - if can_delete: - buffer = 1 - # Warns user if the number is greater than 50 - if a_number > 50: - buffer += 1 - await ctx.channel.send( - content="WARNING: You are about to delete more than 50 messages, are you sure you want to do this?") - reactions = ["✅", "❌"] - for emoji in reactions: - await ctx.channel.last_message.add_reaction(emoji) - await ctx.channel.send( - content="Insert emoji reaction effects here, temporary 10 second wait time until implememnted") - await asyncio.sleep(10) - - async for message in ctx.channel.history(limit=a_number+buffer): - if not message.pinned: - relevant_message = await self.bot.get_channel(ctx.channel.id).fetch_message(message.id) - await relevant_message.delete() - await ctx.channel.send(content='@{} Successfully deleted {} messages'.format(ctx.author, a_number)) - def setup(bot): bot.add_cog(ALBotMessageDeletionHandlers(bot, SQLConnection())) bot.add_cog(ALBotFactorialHandler(bot)) - bot.add_cog(ALBotMessageClear(bot)) From de4d41e67fd3815e6250d705796aacba800a9f4a Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Wed, 22 May 2019 19:24:42 -0400 Subject: [PATCH 26/27] Update gitignore and ALBot.py to match develop Get rid of an artifact from a merge conflict in .gitignore. Also add back missing cogs to ALBot.py and change the command prefix back to ! --- .gitignore | 1 - ALBot.py | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d1e37b8..9e5e39c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ database/data/sqlite3.db praw.ini .idea/ ->>>>>>> 297e1403a8d909bef18e9b8590c6d508c416834f diff --git a/ALBot.py b/ALBot.py index 42fc00d..21b187a 100644 --- a/ALBot.py +++ b/ALBot.py @@ -14,12 +14,15 @@ "cogs.projects", "cogs.admin", "cogs.music", + "cogs.welcome", + "cogs.help", + "cogs.reminder", "cogs.government" ] bot_url = 'https://discordapp.com/api/oauth2/authorize?client_id={0}&scope=bot&permissions=0' -bot = commands.Bot(command_prefix="?", description="ALBot (A Lame Bot)", case_insensitive=True, command_not_found="Invalid command: {}") +bot = commands.Bot(command_prefix="!", description="ALBot (A Lame Bot)", case_insensitive=True, command_not_found="Invalid command: {}") @bot.event async def on_ready(): @@ -38,5 +41,5 @@ async def on_ready(): except Exception as e: exc = '{}: {}'.format(type(e).__name__, e) print('Failed to load extension {}\n{}'.format(extension, exc)) - + bot.run(config.ALBOT_TOKEN) From be3d7ab7cc10fb34696aa28d4b4a34787196774b Mon Sep 17 00:00:00 2001 From: Hunter Jarrell Date: Fri, 7 Jun 2019 20:21:56 -0400 Subject: [PATCH 27/27] Add versions to requirements.txt Add version numbers to the requirements file to limit people testing on the wrong versions. Closes #50 --- requirements.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index c7b2202..b742668 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -discord.py[voice] -youtube_dl -requests -praw +discord.py[voice]==1.1.1 +youtube_dl==2019.6.8 +requests==2.21.0 +praw==6.2.0