Пример #1
0
 async def ping(self, ctx):
     """Shows bot ping."""
     start = time.perf_counter()
     message = await ctx.send(embed=info("Pong!", ctx.me))
     end = time.perf_counter()
     duration = (end - start) * 1000
     await message.edit(
         embed=info(f":ping_pong: {duration:.2f}ms", ctx.me, "Pong!"))
Пример #2
0
 async def slap(self, ctx, member: discord.Member):
     """Slaps a member."""
     if ctx.author == member:
         embed = info(f"{member.mention} slapped him/her self LOL", ctx.me,
                      "Slap!")
         img_url = "https://media.giphy.com/media/j1zuL4htGTFQY/giphy.gif"
     else:
         embed = info(
             f"{member.mention} got slapped in the face by: {ctx.author.mention}!",
             ctx.me, "Slap!")
         img_url = "https://66.media.tumblr.com/05212c10d8ccfc5ab190926912431344/tumblr_mt7zwazvyi1rqfhi2o1_400.gif"
     embed.set_image(url=img_url)
     await ctx.send(embed=embed)
Пример #3
0
 async def shoot(self, ctx, member: discord.Member):
     """Shoots a member."""
     embed = info(
         f"{member.mention} shot by {ctx.author.mention}  :gun: :boom:",
         ctx.me, "Boom!")
     embed.set_image(url="https://i.gifer.com/XdhK.gif")
     await ctx.send(embed=embed)
Пример #4
0
    async def _wait_for(self, container: set,
                        user: discord.User) -> Union[discord.Message, None]:
        """
        Simple custom wait_for that waits for user reply for 5 minutes and has ability to cancel the wait,
        deal with errors and deal with containers (which mark users that are currently doing something aka
        event submission/bug report etc).
        :param container: set, container holding active user sessions by having their IDs in it.
        :param user: Discord user to wait reply from
        :return: Union[Message, None] message representing user reply, can be none representing invalid reply.
        """
        def check(msg):
            return msg.guild is None and msg.author == user

        container.add(user.id)

        await user.send(embed=info(
            "Reply with single message, link to paste service or uploading utf-8 `.txt` file.\n"
            "You have 5m, type `cancel` to cancel right away.", user))

        try:
            user_reply = await self.bot.wait_for("message",
                                                 check=check,
                                                 timeout=300)
        except TimeoutError:
            await user.send(embed=failure("You took too long to reply."))
            container.remove(user.id)
            return

        if user_reply.content.lower() == "cancel":
            await user.send(embed=success("Successfully canceled."))
            container.remove(user.id)
            return

        return user_reply
Пример #5
0
    async def promote(self, ctx, member: discord.Member, role: discord.Role):
        """
        Promote member to role.

        """
        if role >= ctx.author.top_role:
            await ctx.send(
                embed=failure("Role needs to be below you in hierarchy."))
            return
        elif role in member.roles:
            await ctx.send(embed=failure(
                f"{member.mention} already has role {role.mention}!"))
            return

        await member.add_roles(role)

        await ctx.send(embed=success(
            f"{member.mention} is promoted to {role.mention}", ctx.me),
                       delete_after=5)

        dm_embed = info((
            f"You are now promoted to role **{role.name}** in our community.\n"
            f"`'With great power comes great responsibility'`\n"
            f"Be active and keep the community safe."), ctx.me,
                        "Congratulations!")

        dm_embed.set_footer(text="Tortoise community")
        await member.send(embed=dm_embed)
Пример #6
0
    async def on_message_delete(self, message):
        msg = (f"**Message deleted in** {message.channel.mention}\n\n"
               f"**Message: **{message.content}")

        embed = info(msg, message.guild.me, "")
        embed.set_footer(text=f"Author: {message.author}",
                         icon_url=message.author.avatar_url)
        await self.log_channel.send(embed=embed)
Пример #7
0
 async def create_new_suggestion_message(self) -> int:
     suggestions_channel = self.bot.get_channel(
         constants.suggestions_channel_id)
     suggestion_embed = info(self.SUGGESTION_MESSAGE_CONTENT,
                             suggestions_channel.guild.me, "New suggestion")
     msg = await suggestions_channel.send(embed=suggestion_embed)
     suggestion_emoji = self.bot.get_emoji(constants.suggestions_emoji_id)
     await msg.add_reaction(suggestion_emoji)
     return msg.id
Пример #8
0
 async def is_verified(self, ctx, member: DatabaseMember):
     try:
         response = await self.bot.api_client.is_verified(member)
     except ResponseCodeError as e:
         msg = f"Something went wrong, got response status {e.status}.\nDoes the member exist?"
         await ctx.send(embed=failure(msg))
     else:
         await ctx.send(
             embed=info(f"Verified: {response}", ctx.me, title=f"{member}"))
Пример #9
0
 async def _deal_with_vulgar_words(self, message: Message):
     for category, banned_words in self.banned_words.loaded.items():
         for banned_word in banned_words:
             if banned_word in message.content.lower():
                 embed = info(
                     f"Curse word **{banned_word}** detected from the category **{category}**",
                     message.guild.me, "")
                 embed.set_footer(text=f"Author: {message.author}",
                                  icon_url=message.author.avatar_url)
                 await self.log_channel.send(embed=embed)
Пример #10
0
 async def ask(self, ctx):
     content = (
         "Don't ask to ask just ask.\n\n"
         " • You will have much higher chances of getting an answer\n"
         " • It saves time both for us and you as we can skip the whole process of actually getting the "
         "question out of you\n\n"
         "For more info visit https://dontasktoask.com/")
     embed = info(content, ctx.me, "")
     message = await ctx.send(embed=embed)
     await RemovableMessage.create_instance(self.bot, message, ctx.author)
Пример #11
0
 async def show_data(self, ctx, member: DatabaseMember):
     try:
         data = await self.bot.api_client.get_member_data(member)
     except ResponseCodeError as e:
         msg = f"Something went wrong, got response status {e.status}.\nDoes the member exist?"
         await ctx.send(embed=failure(msg))
     else:
         pretty = "\n".join(f"{key}:{value}\n"
                            for key, value in data.items())
         await ctx.send(embed=info(pretty, ctx.me, "Member data"))
Пример #12
0
    async def pfp(self, ctx, member: discord.Member = None):
        """Displays the profile picture of a member."""
        if member is None:
            message, url = "Your avatar", ctx.author.avatar_url
        elif member == ctx.me:
            message, url = "My avatar", member.avatar_url
        else:
            message, url = f"{member} avatar", member.avatar_url

        embed = info(message, ctx.me)
        embed.set_image(url=url)
        await ctx.send(embed=embed)
Пример #13
0
    async def rules(self, ctx):
        """
        Shows all rules info.
        """
        embed_body = []
        for rule_dict in self._rules:
            rule_entry = (
                f"{rule_dict['number']}. Aliases: {', '.join(rule_dict['alias'])}\n"
                f"{rule_dict['statement']}")
            embed_body.append(rule_entry)

        rules_embed = info("\n\n".join(embed_body), ctx.guild.me, "Rules")
        await ctx.send(embed=rules_embed)
Пример #14
0
    async def rule(self, ctx, alias: Union[int, str]):
        """
        Shows rule based on number order or alias.
        """
        if isinstance(alias, int):
            rule_dict = self._get_rule_by_value(alias)
        else:
            rule_dict = self._get_rule_by_alias(alias)

        if rule_dict is None:
            await ctx.send(embed=failure("No such rule."), delete_after=5)
        else:
            await ctx.send(embed=info(rule_dict["statement"], ctx.guild.me, f"Rule {alias}"))
Пример #15
0
    async def _security_check(self, message):
        if "https:" in message.content or "http:" in message.content:
            # Find any url
            base_url = re.findall(
                r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",
                message.content
            )

            for invite in base_url:
                # Get the endpoint of that url (for discord invite url shorteners)
                try:
                    async with self.session.get(invite) as response:
                        invite = str(response.url)
                except aiohttp.ClientConnectorError:
                    # The link is not valid
                    continue

                if "discord.com/invite/" in invite or "discord.gg/" in invite:
                    if not await Security.check_if_invite_is_our_guild(invite, message.guild):
                        # TODO give him warning points etc / send to deterrence channel
                        embed = info(
                            f"{message.author.mention} You are not allowed to send other server invites here.",
                            message.guild.me,
                            title=""
                        )
                        await message.channel.send(embed=embed)
                        await message.delete()

        for category, banned_words in self.banned_words.loaded.items():
            for banned_word in banned_words:
                if banned_word in message.content.lower():
                    embed = info(
                        f"Curse word **{banned_word}** detected from the category **{category}**",
                        message.guild.me,
                        ""
                    )
                    embed.set_footer(text=f"Author: {message.author}", icon_url=message.author.avatar_url)
                    await self.log_channel.send(embed=embed)
Пример #16
0
    async def on_message_edit(self, msg_before, msg_after):
        if msg_before.content == msg_after.content:
            return

        msg = (f"**Message edited in** {msg_before.channel.mention}\n\n"
               f"**Before:** {msg_before.content}\n"
               f"**After: **{msg_after.content}\n\n"
               f"[jump]({msg_after.jump_url})")

        embed = info(msg, msg_before.guild.me)
        embed.set_footer(text=f"Author: {msg_before.author}",
                         icon_url=msg_before.author.avatar_url)
        await self.log_channel.send(embed=embed)
        await self._security_check(msg_after)
Пример #17
0
    async def rules(self, ctx):
        """
        Shows all rules info.
        """
        embed_body = []
        for rule_dict in self._rules:
            rule_entry = (
                f"{rule_dict['number']}. Aliases: {', '.join(rule_dict['alias'])}\n"
                f"{rule_dict['statement']}")
            embed_body.append(rule_entry)

        rules_embed = info("\n\n".join(embed_body), ctx.guild.me, "Rules")

        message = await ctx.send(embed=rules_embed)
        await RemovableMessage.create_instance(self.bot, message, ctx.author)
Пример #18
0
 async def markdown(self, ctx):
     content = (
         "You can format your code by using markdown like this:\n\n"
         "\\`\\`\\`python\n"
         "print('Hello world')\n"
         "\\`\\`\\`\n\n"
         "This would give you:\n"
         "```python\n"
         "print('Hello world')```\n"
         "Note that character ` is not a quote but a backtick.\n\n"
         "If, however, you have large amounts of code then it's better to use our paste service: "
         f"{tortoise_paste_service_link}")
     embed = info(content, ctx.me, "")
     message = await ctx.send(embed=embed)
     await RemovableMessage.create_instance(self.bot, message, ctx.author)
Пример #19
0
    async def show_warnings(self, ctx, member: discord.Member):
        """Shows all warnings of member."""
        warnings = await self.bot.api_client.get_member_warnings(member.id)

        if not warnings:
            await ctx.send(embed=info("No warnings.", ctx.me))

        for count, sub_dict in enumerate(warnings):
            formatted_warnings = [f"{key}:{value}" for key, value in sub_dict.items()]

            warnings_msg = "\n".join(formatted_warnings)
            # TODO temporal quick fix for possible too long message, to fix when embed navigation is done
            warnings_msg = warnings_msg[:1900]

            warnings_embed = thumbnail(warnings_msg, member, f"Warning #{count+1}")
            await ctx.send(embed=warnings_embed)
Пример #20
0
    async def stats(self, ctx):
        """
        Show bot information (stats/links/etc).
        """
        bot_ram_usage = self.process.memory_full_info().rss / 1024**2
        bot_ram_usage = f"{bot_ram_usage:.2f} MB"
        bot_ram_usage_field = self.construct_load_bar_string(
            self.process.memory_percent(), bot_ram_usage)

        virtual_memory = psutil.virtual_memory()
        server_ram_usage = f"{virtual_memory.used/1024/1024:.0f} MB"
        server_ram_usage_field = self.construct_load_bar_string(
            virtual_memory.percent, server_ram_usage)

        cpu_count = psutil.cpu_count()

        bot_cpu_usage = self.process.cpu_percent()
        if bot_cpu_usage > 100:
            bot_cpu_usage = bot_cpu_usage / cpu_count
        bot_cpu_usage_field = self.construct_load_bar_string(bot_cpu_usage)

        server_cpu_usage = psutil.cpu_percent()
        if server_cpu_usage > 100:
            server_cpu_usage = server_cpu_usage / cpu_count
        server_cpu_usage_field = self.construct_load_bar_string(
            server_cpu_usage)

        io_counters = self.process.io_counters()
        io_read_bytes = f"{io_counters.read_bytes/1024/1024:.3f}MB"
        io_write_bytes = f"{io_counters.write_bytes/1024/1024:.3f}MB"

        # The weird numbers is just guessing number of spaces so the lines align
        # Needed since embeds are not monospaced font
        field_content = (
            f"**Bot RAM usage:**{embed_space*7}{bot_ram_usage_field}\n"
            f"**Server RAM usage:**{embed_space}{server_ram_usage_field}\n"
            f"**Bot CPU usage:**{embed_space*9}{bot_cpu_usage_field}\n"
            f"**Server CPU usage:**{embed_space*3}{server_cpu_usage_field}\n"
            f"**IO (r/w):** {io_read_bytes} / {io_write_bytes}\n")

        embed = info("", ctx.me, title="")
        embed.set_author(name="Tortoise BOT", icon_url=ctx.me.avatar_url)
        embed.add_field(name="Bot Stats", value=field_content)
        embed.set_footer(text="Tortoise Community")

        await ctx.send(embed=embed)
Пример #21
0
    async def rules(self, ctx):
        """
        Shows all rules info.
        """
        embed_body = []
        for rule_dict in self._rules:
            rule_entry = (f"**{rule_dict['number']}. {rule_dict['name']}**\n"
                          f"{rule_dict['statement']}\n"
                          f"[**aliases: **{', '.join(rule_dict['alias'])}]")
            embed_body.append(rule_entry)

        rules_embed = info("\n\n".join(embed_body), ctx.guild.me,
                           f"{ctx.guild.name} Rules")
        rules_embed.set_footer(text="Tortoise Community")
        rules_embed.set_thumbnail(url=ctx.guild.icon_url)

        message = await ctx.send(embed=rules_embed)
        await RemovableMessage.create_instance(self.bot, message, ctx.author)
Пример #22
0
    async def verify_member(self, member_id: str):
        """
        Adds verified role to the member and also sends success messages.
        :param member_id: str member id to verify
        """
        try:
            member_id = int(member_id)
        except ValueError:
            raise EndpointBadArguments()

        none_checks = (self.tortoise_guild, self.verified_role,
                       self.unverified_role,
                       self.successful_verifications_channel,
                       self.welcome_channel)

        for check_none in none_checks:
            if check_none is None:
                logger.info(
                    f"One of necessary IDs was not found {none_checks}")
                raise DiscordIDNotFound()

        member = self.tortoise_guild.get_member(member_id)

        if member is None:
            logger.critical(
                f"Can't verify, member is not found in guild {member} {member_id}"
            )
            raise DiscordIDNotFound()

        try:
            await member.remove_roles(self.unverified_role)
        except HTTPException:
            logger.warning(
                f"Bot could't remove unverified role {self.unverified_role}")

        await member.add_roles(self.verified_role)
        await self.successful_verifications_channel.send(
            embed=info(f"{member} is now verified.", member.guild.me, title="")
        )

        msg = (f"You are now verified {self.verified_emoji}\n\n"
               f"Make sure to read {self.welcome_channel.mention}")
        await member.send(embed=success(msg))
Пример #23
0
    async def fetch_doc_links(self, ctx, key, obj):
        page_types = {
            'latest': 'https://discordpy.readthedocs.io/en/latest',
            'python': 'https://docs.python.org/3',
        }

        if obj is None:
            await ctx.send(page_types[key])
            return

        if not self._doc_cache:
            await ctx.trigger_typing()
            await self.build_documentation_lookup_table(page_types)

        obj = re.sub(r'^(?:discord\.(?:ext\.)?)?(?:commands\.)?(.+)', r'\1',
                     obj)

        if key.startswith('latest'):
            # point the abc.Messageable types properly:
            q = obj.lower()
            for name in dir(discord.abc.Messageable):
                if name[0] == '_':
                    continue
                if q == name:
                    obj = f'abc.Messageable.{name}'
                    break

        cache = list(self._doc_cache[key].items())

        matches = Fuzzy.finder(obj, cache, key=lambda t: t[0], lazy=False)[:8]

        if len(matches) == 0:
            await ctx.send(embed=failure("Query didn't match any entity"))
            return

        embed_msg = "\n".join(f"[`{key}`]({url})" for key, url in matches)
        embed_msg = info(embed_msg, ctx.me, title="Links")

        await ctx.send(embed=embed_msg)
Пример #24
0
    async def countdown(self, ctx, start: int):
        try:
            await ctx.message.delete()
        except discord.Forbidden:
            pass

        if self.countdown_started:
            return await ctx.send(
                embed=info("There is already an ongoing timer", ctx.me, ""))

        self.countdown_started = True
        message = await ctx.send(start)
        while start:
            minutes, seconds = divmod(start, 60)
            content = f"{minutes:02d}:{seconds:02d}"
            try:
                await message.edit(content=content)
            except discord.HTTPException:
                break
            start -= 1
            await asyncio.sleep(1)
        self.countdown_started = False
        await message.delete()
Пример #25
0
 async def zen(self, ctx):
     zen = """
         Beautiful is better than ugly.
         Explicit is better than implicit.
         Simple is better than complex.
         Complex is better than complicated.
         Flat is better than nested.
         Sparse is better than dense.
         Readability counts.
         Special cases aren't special enough to break the rules.
         Although practicality beats purity.
         Errors should never pass silently.
         Unless explicitly silenced.
         In the face of ambiguity, refuse the temptation to guess.
         There should be one-- and preferably only one --obvious way to do it.
         Although that way may not be obvious at first unless you're Dutch.
         Now is better than never.
         Although never is often better than *right* now.
         If the implementation is hard to explain, it's a bad idea.
         If the implementation is easy to explain, it may be a good idea.
         Namespaces are one honking great idea -- let's do more of those!
     """
     await ctx.send(
         embed=info(zen, ctx.me, title="The Zen of Python, by Tim Peters"))
Пример #26
0
 async def paste(self, ctx):
     await ctx.send(embed=info(
         f":page_facing_up: {constants.tortoise_paste_service_link}",
         ctx.me,
         title=""))
Пример #27
0
 async def members(self, ctx):
     """Returns the number of members in a server."""
     await ctx.send(
         embed=info(f"{ctx.guild.member_count}", ctx.me, "Member count"))
Пример #28
0
 async def github(self, ctx):
     """GitHub repository"""
     embed = info(f"[Tortoise github repository]({github_repo_link})",
                  ctx.me, "Github")
     await ctx.send(embed=embed)
Пример #29
0
 async def create_message(self, destination) -> None:
     self._message = await destination.send(
         embed=info(self.get_message_content(),
                    self._get_bot_member_from_destination(destination),
                    title=self._embed_title))
Пример #30
0
 async def update_message(self):
     await self._message.edit(embed=info(
         self.get_message_content(),
         self._get_bot_member_from_destination(self._message.channel),
         title=self._embed_title))