Пример #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!"))
 async def deadline(self, ctx):
     """Shows how much time until Code Jam is over."""
     try:
         time_until_string = get_utc_time_until(year=2020, month=11, day=17, hour=23, minute=59, second=59)
         await ctx.send(embed=info(time_until_string, ctx.me, title="Code Jam ends in:"))
     except ValueError:
         await ctx.send(embed=info("Code Jam is over!", member=ctx.me, title="Finished"))
Пример #3
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)
Пример #4
0
 async def on_member_join(self, member: Member):
     inviter = await self.tracker.track_invite()
     if inviter:
         await self.log_channel.send(embed=embed_handler.info(
             f"New member {member} was invited by {inviter}",
             member=member,
             title=""
         ))
     else:
         await self.log_channel.send(embed=embed_handler.info(
             f"New member {member} joined through discord Discovery",
             member=member,
             title=""
         ))
Пример #5
0
    async def _mass_ban_timestamp_helper(self, ctx, timestamp_start: datetime, timestamp_end: datetime, reason: str):
        members_to_ban = []

        for member in self.tortoise_guild.members:
            if member.joined_at is None:
                continue

            if timestamp_start < member.joined_at < timestamp_end:
                members_to_ban.append(member)

        if not members_to_ban:
            return await ctx.send(embed=failure("Could not find any members, aborting.."))

        members_to_ban.sort(key=lambda m: m.joined_at)

        reaction_msg = await ctx.send(
            embed=warning(
                f"This will ban {len(members_to_ban)} members, "
                f"first one being {members_to_ban[0]} and last one being {members_to_ban[-1]}.\n"
                f"Are you sure you want to continue?"
            )
        )

        confirmation = await ConfirmationMessage.create_instance(self.bot, reaction_msg, ctx.author)
        if confirmation:

            one_tenth = len(members_to_ban) // 10
            notify_interval = one_tenth if one_tenth > 50 else 50

            await ctx.send(
                embed=info(
                    f"Starting the ban process, please be patient.\n"
                    f"You will be notified for each {notify_interval} banned members.",
                    ctx.author
                )
            )
            logger.info(f"{ctx.author} is timestamp banning: {', '.join(str(member.id) for member in members_to_ban)}")

            for count, member in enumerate(members_to_ban):
                if count != 0 and count % notify_interval == 0:
                    await ctx.send(embed=info(f"Banned {count} members..", ctx.author))

                await ctx.guild.ban(member, reason=reason)

            message = f"Successfully mass banned {len(members_to_ban)} members!"
            await ctx.send(embed=success(message))
            await self.deterrence_log_channel.send(embed=authored(message, author=ctx.author))
        else:
            await ctx.send(embed=info("Aborting mass ban.", ctx.me))
Пример #6
0
    async def deal_with_long_code(self, message: Message) -> bool:
        """
        When someone sends long message containing code, bot will delete it and upload message content
        to our pastebin and reply with it's link.
        Guessing is quite CPU intensive so be sure to check it only for long messages (not for each).
        :param message: message to check
        :return: bool, was the passed message deleted or not?
        """
        if len(message.content) <= constants.max_message_length:
            return False

        await message.channel.trigger_typing()
        language = await self.bot.loop.run_in_executor(
            None,
            functools.partial(self.guess_language.language_name,
                              source_code=message.content))

        if not language or language == "Markdown":
            # Markdown can be too similar to just regular Discord message so just ignore it.
            # Also ignore if language could not be detected.
            return False

        pastebin_link = await self.create_pastebin_link(
            message.content.encode())
        await message.delete()
        msg = (
            f"Hey {message.author}, I've uploaded your long **{language}** code to our pastebin: {pastebin_link}"
        )
        await message.channel.send(embed=info(msg, message.guild.me, ""))
        return True
Пример #7
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)
Пример #8
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)
Пример #9
0
    async def change_volume(self, ctx, *, volume: float):
        """Change the player volume.
        Parameters
        ------------
        volume: float or int [Required]
            The volume to set the player to in percentage. This must be between 1 and 100.
        """
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send(
                embed=failure("I am not currently connected to voice!"))

        if not 0 < volume < 101:
            return await ctx.send(
                embed=failure("Please enter a value between 1 and 100."))

        player = self.get_player(ctx)

        if vc.source:
            vc.source.volume = volume / 100

        player.volume = volume / 100
        await ctx.send(
            embed=info(f"**`{ctx.author}`** set the volume to **{volume}%**",
                       ctx.me,
                       title="Volume update"))
Пример #10
0
    async def create_source(cls, ctx, search: str, *, loop, download=False):
        loop = loop or asyncio.get_event_loop()

        to_run = partial(ytdl.extract_info, url=search, download=download)
        data = await loop.run_in_executor(None, to_run)

        if "entries" in data:
            # take first item from a playlist
            data = data["entries"][0]

        await ctx.send(embed=info(
            f"```ini\n[Added {data['title']} to the queue.]```", ctx.me, ""))

        if download:
            source = ytdl.prepare_filename(data)
        else:
            return {
                "webpage_url": data["webpage_url"],
                "requester": ctx.author,
                "title": data["title"]
            }

        return cls(discord.FFmpegPCMAudio(source, **ffmpeg_options),
                   data=data,
                   requester=ctx.author)
Пример #11
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:
            container.remove(user.id)
            await user.send(embed=failure("You took too long to reply."))
            return

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

        return user_reply
Пример #12
0
 async def choice(self, ctx, *, args):
     """Returns a randomly chosen string from given arguments"""
     choices = args.split(",")
     if len(choices):
         choice = random.choice(choices)
         await ctx.send(embed=info(
             f"🎰 | Random choice | **{choice.strip()}**", ctx.me, title=""))
Пример #13
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.new_member_role,
                       self.successful_verifications_channel,
                       self.welcome_channel)

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

        # Attempt to fix bug with verification where sometimes member is not found in cache even if they are in guild
        tortoise_guild = self.bot.get_guild(constants.tortoise_guild_id)
        member = 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()

        await member.add_roles(self.verified_role,
                               self.new_member_role,
                               reason="Completed Oauth2 Verification")
        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 self.general_channel.send(
            member.mention,
            embed=info(f"Say hi to our newest member {member.mention}",
                       member.guild.me,
                       title=""),
            delete_after=100)
        await member.send(embed=success(msg))
Пример #14
0
 async def invite(self, ctx):
     """Shows invite to our Tortoise Advent of Code leaderboard."""
     invite_embed = info(
         f"Use this code to join Tortoise AoC leaderboard: **{self.TORTOISE_LEADERBOARD_INVITE}**\n\n"
         "To join you can go to the AoC website: https://adventofcode.com/2020/leaderboard",
         title="Tortoise AoC",
         member=ctx.guild.me)
     await ctx.send(embed=invite_embed)
Пример #15
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
         )
     )
Пример #16
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
         )
     )
Пример #17
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}"))
Пример #18
0
 async def dice(self, ctx, times: int = 1):
     """Rolls a dice"""
     if times == 1:
         dice_roll = random.randint(1, 6)
         await ctx.send(embed=info(
             f"🎲 | Dice Roll | **{dice_roll}**", ctx.me, title=""))
     elif times <= 25:
         dice_roll = ", ".join(
             str(random.randint(1, 6)) for _ in range(times))
         await ctx.send(
             embed=info(f"🎲 | Dice Rolled {times} times | **{dice_roll}**",
                        ctx.me,
                        title=""))
     else:
         await ctx.send(embed=info(
             "Oops! You can't roll that many times. Try a number less than 25",
             ctx.me,
             title=""))
Пример #19
0
 async def shuffle(self, ctx, *, args):
     """Returns a shuffled sequence of given arguments"""
     choices = [word.strip() for word in args.split(",")]
     if len(choices):
         random.shuffle(choices)
         await ctx.send(
             embed=info(f"📃 | Random shuffle | **{', '.join(choices)}**",
                        ctx.me,
                        title=""))
Пример #20
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
Пример #21
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"))
Пример #22
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"
         " • We can skip the whole process of actually getting the question out of you thus you will get "
         "answer faster\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)
Пример #23
0
    async def on_message_delete(self, message):
        if message.content == "":
            return  # if it had only attachment for example

        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)
Пример #24
0
 async def coin(self, ctx, times: int = 1):
     """Tosses a coin"""
     sample_space = ("Head", "Tail")
     if times == 1:
         coin_toss = sample_space[random.randint(0, 1)]
         await ctx.send(embed=info(
             f":coin: | Coin Toss | **{coin_toss}**", ctx.me, title=""))
     elif times <= 25:
         coin_toss = ", ".join(sample_space[random.randint(0, 1)]
                               for _ in range(times))
         await ctx.send(embed=info(
             f":coin: | Coin tossed {times} times | **{coin_toss}**",
             ctx.me,
             title=""))
     else:
         await ctx.send(embed=info(
             "Oops! You can't toss that many times. Try a number less than 25",
             ctx.me,
             title=""))
Пример #25
0
 async def submit(self, ctx):
     """Initializes process of submitting code for event."""
     fake_payload = SimpleNamespace()
     fake_payload.user_id = ctx.author.id
     fake_payload.emoji = self.bot.get_emoji(constants.event_emoji_id)
     await self.bot.get_cog("TortoiseDM").on_raw_reaction_add_helper(
         fake_payload)
     await ctx.send(embed=info(
         "Check your DMs.\n"
         "Note: if you already have active DM option nothing will happen.",
         ctx.me))
    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: {rule_dict['name']}"))
Пример #27
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)
Пример #28
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)
Пример #29
0
 async def on_first_ready(self):
     self.load_extensions()
     await self.change_presence(activity=discord.Game(name="DM me!"))
     await self.reload_tortoise_meta_cache()
     try:
         version = subprocess.check_output(["git", "describe", "--always"
                                            ]).strip().decode("utf-8")
         bot_log_channel = self.get_channel(bot_log_channel_id)
         await bot_log_channel.send(embed=info(
             f"Bot restarted. Image version `{version}`", self.user, ""))
     except Exception as e:
         logger.info("Git image version not found", e)
Пример #30
0
    async def deal_with_attachments(self, message: Message) -> bool:
        """
        Will delete message if it has attachment that we don't allow.
        If it's a whitelisted extension it will upload it's content to our pastebin instead
        and reply with link to it.
        :param message: message to check for attachments
        :return: bool, was the passed message deleted or not?
        """
        reply = None
        delete_message_flag = False

        for attachment in message.attachments:
            try:
                extension = attachment.filename.rsplit('.', 1)[1]
            except IndexError:
                extension = ""  # file has no extension

            extension = extension.lower()

            if extension in extension_to_pastebin:
                # Maximum file size to upload to Pastebin is 4MB
                if attachment.size > 4 * 1024 * 1024:
                    delete_message_flag = True
                    reply = (
                        f"Hey {message.author} , your {extension} file is over 4MB so I will be deleting it.\n\n"
                        f"If you have a question please have a minimum reproducible code example."
                    )
                else:
                    file_content = await attachment.read()
                    url = await self.create_pastebin_link(file_content)
                    reply = (
                        f"Hey {message.author} , I've uploaded your file to our pastebin for easier viewing: "
                        f"[**{attachment.filename}** {url}]")
            elif extension not in allowed_file_extensions:
                reply = (
                    f"Hey {message.author}, {extension} file extension is not allowed here.\n "
                    "If you believe this is a mistake please contact admins.")

            if reply:
                delete_message_flag = True
                msg = await message.channel.send(f"{message.author.mention}!",
                                                 embed=info(
                                                     reply, message.guild.me))
                self.bot.loop.create_task(
                    RemovableMessage.create_instance(self.bot, msg,
                                                     message.author))

        if delete_message_flag:
            await message.delete()

        # for return handler to know if og msg got deleted, so it doesn't run additional checks
        return delete_message_flag