Exemple #1
0
    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}")
Exemple #2
0
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
Exemple #3
0
 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)
Exemple #4
0
    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
Exemple #5
0
    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}`.")
Exemple #6
0
    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
Exemple #7
0
    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")
Exemple #8
0
    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.")
Exemple #9
0
    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
Exemple #10
0
    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)
Exemple #11
0
        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