async def deletelink(self, ctx, *, args=None): # check to see if private channel exists, if not makes one if args is None: await ctx.send("Please use the syntax '!deletelink [COURSE/TOPIC]'" ) return # clean the args to prevent sql injection args = dbcon.sanitize(args) coursename = args c.execute( f"SELECT course, url, description FROM links WHERE course='{coursename}' COLLATE NOCASE;" ) info = c.fetchall() if info is None: await ctx.send(f"No links for {coursename} found") return counter = 0 embed = discord.Embed(title=coursename, color=0xf03413) for i in info: embed.add_field(name=f"{i[2]}", value=f"{i[1]}", inline=False) counter += 1 embed.set_footer(text=f"Total links: {counter}") # there is a 6000 char limit to embeds if len(embed) > 5999: print(f'its over 6000! {coursename}') await ctx.send(embed=embed, content=None) await ctx.send("Please tell me the title of the link to delete:" "\n**WARNING: CANNOT BE UNDONE**") link = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) link = dbcon.sanitize(link.content) c.execute( f"SELECT description, course FROM links WHERE description='{link}' AND course='{coursename}' COLLATE NOCASE;" ) verify = c.fetchone() if verify is None: await ctx.send("Link not found") return try: c.execute( f"DELETE FROM links WHERE course='{coursename}' COLLATE NOCASE AND description='{link}' COLLATE NOCASE;" ) conn.commit() except sqlite3.Error as e: print(type(e).__name__) except: await ctx.send("Hmmm.... something went wrong") return print(f'{ctx.author} Deleted {link} from {coursename}') await ctx.author.dm_channel.send(f'"{link}" deleted') return
async def prof_quote(self, ctx, *, args=None): if args is None: c.execute('SELECT quote, prof FROM profquotes') else: dbcon.sanitize(args) c.execute( f"SELECT quote, prof FROM profquotes WHERE prof='{args}' COLLATE NOCASE;" ) pq = c.fetchall() if len(pq) == 0: await ctx.send(f"No quote from {args} found :man_shrugging:") response = random.choice(pq) await ctx.send(str(response[0]) + " - " + str(response[1]))
async def makequiz(self, ctx, *, arg=None): # check to see if private channel exists, if not makes one if ctx.author.dm_channel is None: await ctx.author.create_dm() if arg is None: await ctx.send( "Please enter a name of the quiz\nEg: !makequiz Ken Trivia") return # clean the arg to prevent SQL injection arg = dbcon.sanitize(arg) quizname = str(arg) c.execute("SELECT name FROM quiz WHERE name='" + quizname + "';") q = c.fetchone() if q is not None: await ctx.send("A quiz by that name already exists") return try: sql = "INSERT INTO quiz (name, questions, madeby, score) VALUES (?, ?, ?, ?)" c.execute(sql, (quizname, 0, str(ctx.author), 100)) conn.commit() except sqlite3.Error as e: print(type(e).__name__) except: await ctx.author.dm_channel.send( "Something went wrong adding the quiz\nQuizname: " + quizname + "\nauthor: " + str(ctx.author)) return else: await ctx.author.dm_channel.send("Quiz created. Type '!addq " + quizname + "' to add questions to this quiz") return
async def define(self, ctx, arg=None): if arg is None: await ctx.send("What **word** would you like the definition of?") word = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) arg = word.content app_id = os.getenv('DEFINE_ID') app_key = os.getenv('DEFINE_KEY') endpoint = "entries" language_code = "en-us" word_id = sanitize(arg) url = "https://od-api.oxforddictionaries.com/api/v2/" + endpoint + "/" + language_code + "/" + word_id.lower( ) async with ctx.typing(): r = requests.get(url, headers={ "app_id": app_id, "app_key": app_key }) p = r.json() # print("code {}\n".format(r.status_code)) # print("text \n" + r.text) # print("json \n" + json.dumps(r.json())) await ctx.send( f'**{p["word"]}** *{p["results"][0]["lexicalEntries"][0]["lexicalCategory"]["text"]}*: ' f'{p["results"][0]["lexicalEntries"][0]["entries"][0]["senses"][0]["definitions"][0]}' )
async def quiz(self, ctx, *, args=None): # If there is no course specified info = None name = None channelname = ctx.channel.name.split('_') name = channelname[0] print(name) c.execute( f"SELECT name, questions, madeby, score FROM quiz WHERE name='{str.lower(name)}';" ) info = c.fetchone() if args is None: # If there is no course specified but you are in a course channel (ie 'cosc111_computer-programming') if info is not None: author = str(info[2]).split('#') quizname = name desc = "" desc += "\nNumber of Questions: " + info[1] desc += "\nMade by: " + author[0] embed = discord.Embed(title=quizname, description=desc, color=0x206694) await ctx.send( "I found a quiz for this channel: \n(Type '!quiz run' to start the quiz)" ) await ctx.send(embed=embed, content=None) return # no quiz specified and not a course channel await ctx.send("'!quiz [NAME]' to run a quiz\n" "'!quizlist' to see list of quizzes\n" "'!addquiz [NAME]' to add a quiz\n" "'!delquiz [NAME]' to delete a quiz\n" "'!addq [QUIZNAME]' to add a question to a quiz") return # run quiz for current channel if args == 'run': if info is None: await ctx.send( "No quiz found for this channel\nType '!quizlist' to see a list of all quizzes" ) return await run(self, ctx, name) return # clean the args to prevent SQL injection args = dbcon.sanitize(args) c.execute(f"SELECT name FROM quiz WHERE name='{args}';") quizinfo = c.fetchone() if quizinfo is None: await ctx.send( "Quiz not found\nType '!quizlist' to see a list of all quizzes" ) return else: await ctx.send('Starting quiz... Type !end to stop') await run(self, ctx, args) return
async def links(self, ctx): userinput = ctx.message.content.split(' ') # If there is no course specified if len(userinput) < 2: channelname = ctx.channel.name.split('_') name = channelname[0] c.execute( f"SELECT course, url, description FROM links WHERE course='{name}' COLLATE NOCASE;" ) info = c.fetchall() # If there is no course specified but you are in a course channel (ie 'cosc111_computer-programming') if len(info) >= 1: await ctx.send("*Warning: Follow links at your own risk!*") coursename = str.upper(name) counter = 0 embed = discord.Embed(title=coursename, color=0xf03413) for i in info: embed.add_field(name=f"{i[2]}", value=f"{i[1]}", inline=False) counter += 1 embed.set_footer(text=f'Total links = {counter}') await ctx.send(embed=embed, content=None) return # no course specified and not a course channel else: await ctx.send( "Please enter '!links' followed by a course code\nEg: !links COSC111" ) return # returns the specific course/topic (even if you are in course channel) coursename = dbcon.sanitize(userinput[1]) c.execute( f"SELECT course, url, description FROM links WHERE course='{coursename}' COLLATE NOCASE;" ) info = c.fetchall() if info is None: await ctx.send(f"No links for {coursename} found") return await ctx.send("*Warning: Follow links at your own risk!*") counter = 0 embed = discord.Embed(title=coursename, color=0xf03413) for i in info: embed.add_field(name=f"{i[2]}", value=f"{i[1]}", inline=False) counter += 1 embed.set_footer(text=f"Total links: {counter}") # there is a 6000 char limit to embeds if len(embed) > 5999: print(f'its over 6000! {coursename}') await ctx.send(embed=embed, content=None) return
async def courseinfo(self, ctx): userinput = ctx.message.content.split(' ') # If there is no course specified if len(userinput) < 2: channelname = ctx.channel.name.split('_') name = channelname[0] info = c.execute( f"SELECT desc, pre_req, core_req FROM course_info WHERE course_id='{str.lower(name)}';" ) info = info.fetchone() if info is None: await ctx.send( "Please enter '!courseinfo' followed by a course code\nEg: !courseinfo COSC111" ) return # If there is no course specified but you are in a course channel (ie 'cosc111_computer-programming') else: coursename = str.upper(name) desc = info.desc if len(info.pre_req) > 0: desc += "\nPre-reqs: " + info.pre_req if len(info.core_req) > 0: desc += "\nCo-reqs: " + info.core_req embed = discord.Embed(title=coursename, description=desc, color=0x206694) await ctx.send(embed=embed, content=None) return # returns the specific course (even if you are in course channel) coursename = dbcon.sanitize(userinput[1]) info = c.execute( f"SELECT desc, pre_req, core_req FROM course_info WHERE course_id='{str.lower(coursename)}';" ) info = info.fetchone() if info is None: await ctx.send("Class not found") return coursename = str.upper(coursename) desc = info.desc if len(info.pre_req) > 0: desc += "\nPre-reqs: " + info.pre_req if len(info.core_req) > 0: desc += "\nCo-reqs: " + info.core_req embed = discord.Embed(title=coursename, description=desc, color=0x206694) await ctx.send(embed=embed, content=None) return
async def on_message(message): if message.author.bot: # Stops it from replying to bots return userinput = message.content.split(' ') if len(userinput) > 0: name = userinput[0] if name[0] == '!': # log the command and who called it for debugging purposes print( f'Command "{userinput[0]}" called by user "{message.author}" in channel "{message.channel}"' ) # Removes '!' from beginning of command name = dbcon.sanitize(name[1:]) # Checks for a match in the custom commands table c.execute( f"SELECT * FROM customcommands WHERE name='{name}' COLLATE NOCASE;" ) row = c.fetchone() if row is None: # No matching commands were found in database, stops return # if context is multiVal if row[1] == 'multiVal': c.execute( f"SELECT * from multival WHERE name='{name}' COLLATE NOCASE;" ) vals = c.fetchall() response = random.choice(vals) await message.channel.send(response[1]) return if row[1] != 'onMessage': # Commands 'trigger' is not onMessage, stops return if len(userinput) > 1 and userinput[1] == 'help': # Outputs help text if 1st arg is 'help' await message.channel.send('Help for ' + name + ':\n' + row[3]) else: # Outputs content of command await message.channel.send(row[2])
async def delquiz(self, ctx, *, arg=None): if arg is None: await ctx.send( "Please enter a name of the quiz to delete.\nEg: !delquiz Ken Trivia" ) return # clean the arg to prevent SQL injection arg = dbcon.sanitize(arg) quizname = str(arg) c.execute( "SELECT name, questions, madeby, score FROM quiz WHERE name='" + quizname + "';") q = c.fetchone() quizauthor = str(q[2]).split("#") desc = f"Quiz Name: {q[0]}\nNo of Questions: {q[1]}\nMade by: {quizauthor[0]}" embed = discord.Embed(title=q[0], description=desc, color=0x206694) await ctx.send( "Please review the quiz and type 'y' to delete or 'n' to cancel:") await ctx.send(embed=embed, content=None) confirm = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) if confirm.content.startswith('n') or confirm.content.startswith('N'): await ctx.send("Cancelled") return author = str(ctx.author).split("#") # check to see if the quiz author is the same as the message author if author[0] != quizauthor[0]: print(f'{ctx.author} failed to delete command {quizname}') await ctx.send("Quizzes can only be deleted by their author") return try: c.execute("DELETE FROM quiz WHERE name='" + quizname + "';") conn.commit() except sqlite3.Error as e: print(type(e).__name__) except: await ctx.send("Hmmm.... something went wrong") return c.execute("DELETE FROM questions WHERE quizname='" + quizname + "';") await ctx.send(f"{quizname} deleted") print(f"{quizname} deleted by {ctx.author}") return
async def customcommand(self, ctx, *, args=None): if args is not None: args = dbcon.sanitize(args) # add command if args == 'add' or args == 'a': await ctx.send( "What will the name of the command be:\n*(one word only please)*" ) cmdname = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) if " " in cmdname.content: await ctx.send("No spaces please... cc add cancelled") return if cmdname.content in nouse: await ctx.send( f"{cmdname.content} is a restricted word... cc add cancelled" ) return # check to see if cmd already exists c.execute( f"SELECT name FROM customcommands WHERE name='{str(cmdname.content)}';" ) name = c.fetchone() if name is not None: await ctx.send( "A command by that name already exists.\n" "Type '!customcommand list' to see the list of custom commands" ) return await ctx.send( "What context will it be called on:\n" "**1. onMessage** - will activate when called by user (eg '!pizza')\n" "**2. onJoin** - will notify user upon joining server\n" "**3. multiVal** - an onMessage that returns a random response from a list of values\n" "(other types coming in future)") cmdcontext = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) # check to see what the context will be (default is set as 'onMessage') # this should really be a unnamed function context = "onMessage" if cmdcontext.content.startswith( "1") or cmdcontext.content.startswith( "onM") or cmdcontext.content.startswith("onm"): context = "onMessage" if cmdcontext.content.startswith( "2") or cmdcontext.content.startswith( "onJ") or cmdcontext.content.startswith("onj"): context = "onJoin" if cmdcontext.content.startswith( "3") or cmdcontext.content.startswith("mu"): context = "multiVal" # the value the bot returns when the command is called cmdval = "" if context == 'onMessage' or context == 'onJoin': await ctx.send( "What will the return value be:\n*(Discord markdown will apply in the return)*" ) cmdreturn = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) cmdval = cmdreturn.content if context == 'multiVal': addval = [] while (1): await ctx.send("Enter a return:\n*(enter !stop to stop)*") val = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) if val.content == '!stop': break else: addval += [val.content] continue cmdval = "multival" # the help value await ctx.send( f"What will the help value be:\n(what will '!help {cmdname.content}' return?)" ) cmdhelp = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) await ctx.send( "Please review the command and type 'y' to accept or 'n' to cancel:" ) desc = "" desc += "\nName: " + cmdname.content desc += "\nContext: " + context desc += "\nReturn: " + cmdval desc += "\nHelp: " + cmdhelp.content embed = discord.Embed(title=cmdname.content, description=desc, color=0x206694) await ctx.send(embed=embed, content=None) confirm = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) if confirm.content.startswith('n') or confirm.content.startswith( 'N'): await ctx.send("Cancelled") return else: try: sql = "INSERT INTO customcommands (name, context, value, help, author) VALUES (?, ?, ?, ?, ?)" c.execute(sql, (cmdname.content, context, cmdval, cmdhelp.content, str(ctx.author))) conn.commit() if context == 'multiVal': for add in addval: sql = "INSERT INTO multival (name, value) VALUES (?,?)" c.execute(sql, (cmdname.content, add)) conn.commit() await ctx.send("Command added") except sqlite3.Error as e: print(type(e).__name__) except: await ctx.send("Hmmm.... something went wrong") return return # delete command if args == 'del' or args == 'd': await ctx.send( "What is the name of the custom command you would like to delete?" "\n(please do not include the '!')") cmdname = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) if cmdname.content.startswith("!"): await ctx.send("Cancelled cc d") return try: c.execute( "SELECT name, value, context, help, author FROM customcommands WHERE name='" + str(cmdname.content) + "';") except sqlite3.Error as e: print(type(e).__name__) except: await ctx.send("Hmmm.... something went wrong") return cmd = c.fetchone() if cmd is None: await ctx.send( "No command by that name exists.\n" "Type '!customcommand list' to see the list of custom commands" ) return cmdauthor = str(cmd[4]).split("#") desc = f"Value: {cmd[1]}\nContext: {cmd[2]}\nHelp: {cmd[3]}\nMade by: {cmdauthor[0]}" embed = discord.Embed(title=cmdname.content, description=desc, color=0x206694) await ctx.send( "Please review the command and type 'y' to delete or 'n' to cancel:" ) await ctx.send(embed=embed, content=None) confirm = await self.bot.wait_for( 'message', check=lambda message: message.author == ctx.author, timeout=60.0) if confirm.content.startswith('n') or confirm.content.startswith( 'N'): await ctx.send("Cancelled") return author = str(ctx.author).split("#") # if caller is admin, they can delete any command if ctx.message.author.top_role.permissions.administrator: print(f'user is admin') c.execute( f"DELETE FROM customcommands WHERE name='{cmdname.content}';" ) await ctx.send(f"{cmdname.content} deleted") print(f"{cmdname.content} deleted by {ctx.author}") else: if author[0] != cmdauthor[0]: print( f'{ctx.author} failed to delete command {cmdname.content}' ) await ctx.send( "Commands can only be deleted by their author") else: c.execute("DELETE FROM customcommands WHERE name='" + cmdname.content + "';") await ctx.send(f"{cmdname.content} deleted") print(f"{cmdname.content} deleted by {ctx.author}") conn.commit() return # modify command if args == 'mod' or args == 'm': await ctx.send("you have chosen modify\nComing soon") return # list commands if args == 'list' or args == 'l': try: c.execute('SELECT * FROM customcommands') except sqlite3.Error as e: print(type(e).__name__) rows = c.fetchall() customcmds = "" for row in rows: if row[1] == 'onMessage': customcmds += "!" + row[0] + '\n' if row[1] == 'onJoin': customcmds += row[0] + " *(onJoin)*\n" embed = discord.Embed(title="Custom Command List", description=customcmds, color=0x206694) await ctx.send(embed=embed, content=None) return await ctx.send( "'!customcommand add' to add command\n'!customcommand mod' to modify command" "\n'!customcommand del' to delete command\n'!customcommand list' to list custom commands" ) return
async def help(self, ctx): message = ctx.message.content message = message.split(' ') if len(message) <= 1: # If no arguments are provided it will put out a list of all commands desc = "List of all commands for this bot:\n" embed = discord.Embed(title="Help", description=desc, color=0x206694) hardcoded = "" for command in self.bot.commands: if not command.hidden: hardcoded += f"!{command}\n" embed.add_field(name="Hardcoded Commands:", value=hardcoded, inline=False) # Custom commands c.execute('SELECT name, context FROM customcommands ORDER BY name') rows = c.fetchall() customcmds = "" for row in rows: if row[1] == 'onMessage' or row[1] == 'multiVal': customcmds += f'!{row[0]}\n' if row[1] == 'onJoin': customcmds += row[0] + " *(onJoin)*\n" embed.add_field(name="Custom Commands:", value=customcmds, inline=False) # if caller is admin, they get to see all commands HiddenCommands = discord.Embed(title="Help", description=None, color=0x206694) hide = "" for command in self.bot.commands: if command.hidden: hide += f"!{command}\n" HiddenCommands.add_field(name="Admin-only Commands:", value=hide, inline=False) if ctx.message.author.top_role.permissions.administrator: if ctx.author.dm_channel is None: await ctx.author.create_dm() await ctx.author.dm_channel.send(embed=HiddenCommands, content=None) # Outputs to channel await ctx.send(embed=embed, content=None) await ctx.send( "Type '!help [COMMAND]' for additional information about that specific command" ) return else: arg = dbcon.sanitize(message[1]) argtitle = "!" + arg embed = discord.Embed(title=argtitle, color=0x206694) cmdhelp = "" cmdname = arg # Checks for custom commands c.execute("SELECT * FROM customcommands WHERE name='" + arg + "' COLLATE NOCASE;") row = c.fetchone() if row is not None: # Sets the output to the help message of that command cmdhelp += row[3] # find the hardcoded cmd else: cmd = self.bot.get_command(arg) if cmd is None: await ctx.send( "Command not found. Use '!help' to see a list of all commands." ) return cmdhelp = cmd.help cmdname = f"!{cmd.name}" cmdaliases = cmd.aliases if len(cmdaliases) > 0: cmdhelp += '\nAliases: ' + str(cmdaliases) embed.add_field(name=cmdname, value=cmdhelp, inline=False) await ctx.send(embed=embed, content=None) return