async def message(self, context): async def get_destination(context): def check_destination(msg): return msg.author.id == context.message.author.id and msg.channel.id == context.channel.id and msg.channel_mentions await utils.say(context.channel, content="Which channel should the message be sent to?") try: destination = await self.bot.wait_for("message", timeout=60, check=check_destination) return destination.content except asyncio.TimeoutError: return False async def get_message(context): def check_message(msg): return msg.author.id == context.message.author.id and msg.channel.id == context.channel.id await utils.say(context.channel, content="What's your message?") try: message = await self.bot.wait_for("message", timeout=120, check=check_message) return message.content except asyncio.TimeoutError: return False cmd_settings = Settings.command_settings("message", context.guild.id) if not cmd_settings.get("enabled"): return arguments = context.message.content.split(maxsplit=2) destination_id = None msg = "" try: destination_id = arguments[1] except IndexError: destination_id = await get_destination(context) if not destination_id: return CommandStatus.CANCELLED destination_id = destination_id.strip("<># ") destination = discord.utils.find(lambda c: str(c.id) == destination_id, context.guild.text_channels) if not destination: await utils.say(context.channel, content="I couldn't find that channel on this server.") return CommandStatus.INVALID try: msg = arguments[2] except IndexError: msg = await get_message(context) if not msg: return CommandStatus.CANCELLED try: sent = await utils.say(destination, content=msg) except discord.Forbidden: await utils.say(context.channel, content=f"I don't have permission to send messages to {destination.name}") return CommandStatus.FORBIDDEN else: await utils.say(context.channel, content=f"Message sent: {sent.jump_url}")
def regular_lookup(word: str): """Looks up given word in Merriam-Webster Collegiate dictionary Args: word(str): Word to look up in dictionary. Returns: list: Can be a list of DictionaryEntry objects or a list of suggested strings to search up (in case of misspelling) """ entries = [] entries = regular_cache.get_entries(word) if not entries: api_url = Settings.command_settings("define")["base_api_url"] api_key = Settings.config["env"]["dict_regular_api_key"] req_location = f"{api_url}{word}?key={api_key}" response = requests.get(req_location, timeout=30) res_data = response.json() if not res_data: return None # Word not found original_found = False clean_word = re.sub(r"\s+", " ", word.strip().lower()) for i, entry in enumerate(res_data): if isinstance(entry, str): entries.append(entry) elif re.match( r"{word}\W?(?:\:[\d\w]+)?$".format(word=clean_word), entry.get("meta", {"id": ""})["id"], re.I): original_found = True try: # Check for spelling variants if not entry.get("shortdef") and entry.get("cxs"): for variant in regular_lookup(entry["cxs"][0]["cxtis"][0]["cxt"]): entries.append(variant) else: entries.append(DictionaryEntry(entry)) except (IndexError, KeyError) as e: continue elif 0 == i and not entries: try: # Check for spelling variants if not entry.get("shortdef") and entry.get("cxs"): for variant in entry["cxs"][0]["cxtis"]: if variant.get("cxt"): entries.append(variant["cxt"]) else: entries.append(DictionaryEntry(entry)) except (IndexError, KeyError) as e: continue elif not original_found: entries.append(DictionaryEntry(entry)) regular_cache.add_entries(word, entries) return entries
async def on_command_error(self, context, error): cmd_name = context.command.name cmd_settings = Settings.command_settings(cmd_name, context.guild.id) if isinstance(error, discord.ext.commands.MissingPermissions ) and cmd_settings.get("visible"): notice = "You need the following permissions for this command: {}".format( ", ".join([f"`{p}`" for p in error.missing_perms])) await utils.say(context.channel, content=notice) elif isinstance(error, discord.ext.commands.NotOwner): return else: Logger.error(logger, error)
async def exempt(self, context): cmd_settings = Settings.command_settings("exempt", context.guild.id) if not cmd_settings.get("enabled"): return args = context.message.split(maxsplit=2) cmd_type = args[1].lower() if cmd_type == "add": pass elif cmd_type == "remove": pass elif cmd_type == "list": pass
async def define(self, context): args = context.message.clean_content.split(maxsplit=1) if 2 > len(args): await utils.say( context.channel, content= f"Type `{context.prefix}{context.command.name} {context.command.usage}` to look up a term in the dictionary." ) return search_term = re.sub(r"\s+", " ", args[1].strip()) search_results = utils.dictionary.regular_lookup(search_term) if search_results: base_url = Settings.command_settings("define")["base_url"] search_url = requote_uri(f"{base_url}{search_term}") reply = discord.Embed(title=f'Define "{search_term}"', url=search_url) reply.set_footer(text=f"Source: {search_url}") try: num_entries = len(search_results) definitions = [] for i, entry in enumerate(search_results): if i > 2: break is_offensive = " *(offensive)*" if entry.is_offensive else "" term_type = entry.term_type definitions.append( f"**{search_term}** {i + 1}/{num_entries} *({term_type})*{is_offensive}" ) definitions.append("".join( ["*", "\n\n".join(entry.short_definitions), "*"])) definitions.append("\n") reply.description = "\n".join(definitions) except AttributeError: # Suggested search terms reply.url = "" suggestions = "\n".join(search_results) reply.description = f"**Did you mean...**\n*{suggestions}*" await utils.say(context.channel, embed=reply) else: await utils.say( context.channel, content=f"Couldn't find a definition for `{search_term}`.")
async def inactivelist(self, context): cmd_settings = Settings.command_settings(context.command.name, context.guild.id) if not cmd_settings.get("enabled"): return inactive_members = await get_inactive_members(context) inactive_list = [] for i in inactive_members: last_notified = i.last_notified.strftime(" (%b %d, %Y %Z)") if i.last_notified else "" entry = f"{'**EXEMPT** ' if i.is_exempt else ''}{i.user.mention} [{i.user.display_name}]{last_notified}" inactive_list.append(entry) days_threshold = Settings.inactive_threshold(context.guild.id) embeds = utils.split_embeds( title=f"Inactive Members ({days_threshold}+ days since last message)", description="\n".join(inactive_list) ) for i, embed in enumerate(embeds): if i < len(embeds) - 1: await utils.say(context.channel, embed=embed) else: # Final message inactivity_message = Settings.inactive_message(context.guild.id) if inactivity_message: embed.set_footer(text="React 📧 below to notify them") report = await utils.say(context.channel, content=f"{context.author.mention}", embed=embed) if inactivity_message: await report.add_reaction("📧") def check(reaction, user): return reaction.message.id == report.id and user.id == context.message.author.id \ and str(reaction.emoji) == "📧" try: await self.bot.wait_for("reaction_add", timeout=600, check=check) except asyncio.TimeoutError: embed.set_footer(text=discord.Embed.Empty) await report.edit(embed=embed) await report.clear_reactions() else: await self.notify_inactive_members(context, inactive_members) return CommandStatus.COMPLETED
def set_commands(self, *cmds): self.add_cog(commands.Admin(self)) self.add_cog(commands.General(self)) self.add_cog(commands.Statistics(self)) for c in cmds: self.add_cog(c) for command in self.commands: Logger.debug(logger, f"Setting up command '{command.name}'") cmd_settings = Settings.command_settings(command.name) if not cmd_settings: continue command.aliases = cmd_settings.get("aliases", []) command.hidden = not cmd_settings.get("visible", True) command.description = cmd_settings.get("description", "") command.help = cmd_settings.get("help", "") command.usage = cmd_settings.get("usage", "") Logger.debug(logger, f"Command '{command.name}' all set")
async def purgeleaderboard(self, context): cmd_settings = Settings.command_settings("purgeleaderboard", context.guild.id) if not cmd_settings.get("enabled"): return mee6 = mee6_py_api.API(context.guild.id) member_ids = [str(m.id) for m in context.guild.members] try: leaderboard_pages = await mee6.levels.get_all_leaderboard_pages() absent_members = [] for page in leaderboard_pages: players = page.get("players") absent_members.extend([f"**{p.get('username')}**#{p.get('discriminator')} — lv{p.get('level')}" for p in players if p.get("id") not in member_ids]) if not absent_members: continue for embed in utils.split_embeds( title=f"MEE6 leaderboard members who left the server", description="\n".join(absent_members) ): await utils.say(context.channel, embed=embed) except mee6_py_api.exceptions.HTTPRequestError: await utils.say(context.channel, content="I couldn't find this server's MEE6 leaderboard.")
async def edit(self, context): def check_id(msg): return msg.author.id == context.message.author.id and msg.channel.id == context.channel.id def check_message(msg): return msg.author.id == context.message.author.id and msg.channel.id == context.channel.id cmd_settings = Settings.command_settings("edit", context.guild.id) if not cmd_settings.get("enabled"): return # TODO: Let message ID be passed in first go - skip channel arg and loop through all? # arguments = context.message.content.split() message_id = 0 if not context.message.channel_mentions: await utils.say(context.channel, content="To use, put: ```;edit #[channel name]```, where [channel name] is where the message is.") return CommandStatus.INVALID channel = context.message.channel_mentions[0] await utils.say(context.channel, content="Enter the message ID to be edited:") try: message_id = await self.bot.wait_for("message", timeout=300, check=check_id) message_id = message_id.content except asyncio.TimeoutError: await utils.say(context.channel, content="Time's up.") return CommandStatus.CANCELLED try: message_id = int(message_id) except ValueError: await utils.say(context.channel, content=f"{message_id} is not a valid message ID.") return CommandStatus.INVALID to_edit = await channel.fetch_message(message_id) if not to_edit: await utils.say(context.channel, content=f"Couldn't find message with ID #{message_id}.") return CommandStatus.INVALID elif to_edit.author.id != context.guild.me.id: await utils.say(context.channel, content="I can only edit messages I sent.") return CommandStatus.INVALID else: for preview in utils.split_embeds( title="Message Preview", description=discord.utils.escape_markdown(to_edit.content), url=to_edit.jump_url, timestamp=to_edit.edited_at if to_edit.edited_at else to_edit.created_at ): await utils.say(context.channel, embed=preview) await utils.say(context.channel, content="Enter the newly edited message below.") try: new_edit = await self.bot.wait_for("message", timeout=900, check=check_message) except asyncio.TimeoutError: await utils.say(context.channel, content="Time's up.") return CommandStatus.CANCELLED else: try: await to_edit.edit(content=new_edit.content) except discord.Forbidden: await utils.say(context.channel, content="I'm not allowed to edit this message.") return CommandStatus.FORBIDDEN else: await utils.say(context.channel, content=f"Message edited: {to_edit.jump_url}") return CommandStatus.COMPLETED
async def inactivenotify(self, context): cmd_settings = Settings.command_settings(context.command.name, context.guild.id) if not cmd_settings.get("enabled"): return await self.notify_inactive_members(context)
Can be a list of DictionaryEntry objects or a list of suggested strings to search. """ if word in self._cache: self._cache[word]["requests"] += 1 return self._cache[word]["entries"] return [] def _check_entries(self): """Remove entry with least amount of requests if cache is at or over limit""" if len(self._cache) >= self.limit: sorted_cache = [k for k, v in sorted(self._cache.items(), key=lambda item: item[1]["requests"])] self._cache.pop(sorted_cache[0], None) regular_cache = DictionaryCache(limit=Settings.command_settings("define")["cache_limit"]) format_tokens = [ { "start_token": "{b}", "end_token": "{\/b}", "pattern": r"", "start_sub": "**", "end_sub": "**" } ] def format_text(text: str): pass def regular_lookup(word: str): """Looks up given word in Merriam-Webster Collegiate dictionary