示例#1
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)
示例#2
0
    async def ban(self,
                  ctx,
                  member: discord.Member,
                  *,
                  reason="Reason not stated."):
        """
        Bans  member from the guild.

        """
        await member.ban(reason=reason)
        await ctx.send(embed=success(f"{member.name} successfully banned."),
                       delete_after=5)

        deterrence_embed = infraction_embed(ctx, member,
                                            constants.Infraction.ban, reason)
        deterrence_log_channel = self.bot.get_channel(
            constants.deterrence_log_channel_id)
        await deterrence_log_channel.send(embed=deterrence_embed)

        dm_embed = deterrence_embed
        dm_embed.add_field(
            name="Repeal",
            value="If this happened by a mistake contact moderators.")

        await member.send(embed=dm_embed)
示例#3
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
示例#4
0
    async def dm_members(self, ctx, role: discord.Role, *, message: str):
        """
        DMs all member that have a certain role.
        Failed members are printed to log.

        """
        members = (member for member in role.members if not member.bot)
        failed = []
        count = 0

        for member in members:
            dm_embed = discord.Embed(title=f"Message for role {role}",
                                     description=message,
                                     color=role.color)
            dm_embed.set_author(name=ctx.guild.name,
                                icon_url=ctx.guild.icon_url)

            try:
                await member.send(embed=dm_embed)
            except discord.Forbidden:
                failed.append(str(member))
            else:
                count += 1

        await ctx.send(
            embed=success(f"Successfully notified {count} users.", ctx.me))

        if failed:
            logger.info(f"dm_unverified called but failed to dm: {failed}")
示例#5
0
    async def warn(self, ctx, member: discord.Member, *, reason):
        """
        Warns a member.
        Reason length is maximum of 200 characters.

        """
        if len(reason) > 200:
            await ctx.send(
                embed=failure("Please shorten the reason to 200 characters."),
                delete_after=3)
            return

        embed = infraction_embed(ctx, member, constants.Infraction.warning,
                                 reason)
        embed.add_field(
            name="**NOTE**",
            value=("If you are planning to repeat this again, "
                   "the mods may administer punishment for the action."))

        await self.deterrence_log_channel.send(f"{member.mention}",
                                               delete_after=0.5)
        await self.deterrence_log_channel.send(embed=embed)

        await self.bot.api_client.add_member_warning(ctx.author.id, member.id,
                                                     reason)

        await ctx.send(embed=success("Warning successfully applied.", ctx.me),
                       delete_after=5)

        await asyncio.sleep(5)
        await ctx.message.delete()
示例#6
0
    async def dm_unverified(self, ctx):
        """
        Dms all unverified members reminder that they need to verify.
        Failed members are printed to log.

        """
        unverified_role = ctx.guild.get_role(constants.unverified_role_id)
        unverified_members = (member for member in unverified_role.members
                              if member.status == discord.Status.online)
        failed = []
        count = 0

        for member in unverified_members:
            msg = (
                f"Hey {member.mention}!\n"
                f"You've been in our guild **{ctx.guild.name}** for some time..\n"
                f"We noticed you still didn't verify so please go to our channel "
                f"{constants.verification_url} and verify.")

            try:
                await member.send(msg)
            except discord.Forbidden:
                failed.append(str(member))
            else:
                count += 1

        await ctx.send(
            embed=success(f"Successfully notified {count} users.", ctx.me))

        if failed:
            logger.info(f"dm_unverified called but failed to dm: {failed}")
示例#7
0
    async def create_bug_report(self, user: discord.User):
        user_reply = await self._get_user_reply(self.active_bug_reports, user)
        if user_reply is None:
            return

        await self.bug_report_channel.send(f"User `{user}` ID:{user.id} submitted bug report: {user_reply}")
        await user.send(embed=success("Bug report successfully submitted, thank you."))
        self.active_bug_reports.remove(user.id)
示例#8
0
    async def manually_add_database_member(self, ctx, member: Member):
        if await self.bot.api_client.does_member_exist(member.id):
            await ctx.send(embed=warning("Member already exists, aborting.."))
            return

        logger.info(f"{ctx.author} is manually adding member {member} {member.id} to database")
        await self.bot.api_client.insert_new_member(member)
        await ctx.send(embed=success(f"Member {member} successfully added to database."))
示例#9
0
    async def create_suggestion(self, user: discord.User):
        user_reply = await self._get_user_reply(self.active_suggestions, user)
        if user_reply is None:
            return

        msg = await create_suggestion_msg(self.user_suggestions_channel, user, user_reply)
        await self.bot.api_client.post_suggestion(user, msg, user_reply)
        await user.send(embed=success("Suggestion successfully submitted, thank you."))
        self.active_suggestions.remove(user.id)
示例#10
0
 async def unban(self,
                 ctx,
                 user: GetFetchUser,
                 *,
                 reason="Reason not stated."):
     """Unbans  member from the guild."""
     await ctx.guild.unban(user=user, reason=reason)
     await ctx.send(embed=success(f"{user} successfully unbanned."),
                    delete_after=5)
示例#11
0
    async def clear(self, ctx, amount: int, member: discord.Member = None):
        """
        Clears last X amount of messages.
        If member is passed it will clear last X messages from that member.
        """
        def check(msg):
            return member is None or msg.author == member

        await ctx.channel.purge(limit=amount + 1, check=check)
        await ctx.send(embed=success(f"{amount} messages cleared."), delete_after=3)
示例#12
0
    async def create_suggestion(self, user: discord.User):
        user_reply = await self._get_user_reply(self.active_suggestions, user)
        if user_reply is None:
            return

        await self.user_suggestions_channel.send(
            f"User `{user}` ID:{user.id} submitted suggestion: {user_reply}")
        await user.send(
            embed=success("Suggestion successfully submitted, thank you."))
        self.active_suggestions.remove(user.id)
示例#13
0
 async def deny(self,
                ctx,
                message_id: int,
                *,
                reason: str = "No reason specified"):
     """Deny a suggestion"""
     await self._suggestion_helper(ctx, message_id, reason,
                                   constants.SuggestionStatus.denied)
     await ctx.send(embed=success("Suggestion successfully denied."),
                    delete_after=5)
示例#14
0
    async def delete_suggestion(self, ctx, message_id: int):
        """Delete a suggestion"""
        msg: Message = await self.user_suggestions_channel.fetch_message(
            message_id)
        if msg is not None:
            await msg.delete()

        await self.bot.api_client.delete_suggestion(message_id)
        await ctx.send(embed=success("Suggestion successfully deleted."),
                       delete_after=5)
示例#15
0
    async def load(self, ctx, extension_name):
        """
        Loads an extension.
        :param extension_name: cog name without suffix
        """
        self.bot.load_extension(f"bot.cogs.{extension_name}")

        msg = f"{extension_name} loaded."
        logger.info(f"{msg} by {ctx.author.id}")

        await ctx.send(embed=success(msg, ctx.me))
示例#16
0
    async def mute(self, ctx, member: discord.Member, *, reason="No reason stated."):
        """Mutes the member."""
        if self.muted_role in member.roles:
            await ctx.send(embed=failure("Cannot mute as member is already muted."))
            return

        reason = f"Muting member. {reason}"
        await member.add_roles(self.muted_role, reason=reason)
        await member.remove_roles(self.verified_role, reason=reason)
        await ctx.send(embed=success(f"{member} successfully muted."), delete_after=5)
        await self.bot.api_client.add_member_warning(ctx.author.id, member.id, reason)
示例#17
0
    async def create_event_submission(self, user: discord.User):
        user_reply = await self._get_user_reply(self.active_event_submissions, user)
        if user_reply is None:
            return

        await self.code_submissions_channel.send(
            f"User `{user}` ID:{user.id} submitted code submission: "
            f"{user_reply}"
        )
        await user.send(embed=success("Event submission successfully submitted."))
        self.active_event_submissions.remove(user.id)
示例#18
0
    async def unmute(self, ctx, member: discord.Member):
        """Unmutes the member."""
        if self.muted_role not in member.roles:
            await ctx.send(embed=failure("Cannot unmute as member is not muted."))
            return

        reason = f"Unmuted by {ctx.author.id}"

        await member.remove_roles(self.muted_role, reason=reason)
        await member.add_roles(self.verified_role, reason=reason)

        await ctx.send(embed=success(f"{member} successfully unmuted."), delete_after=5)
示例#19
0
    async def reload(self, ctx, extension_name):
        """
        Reloads an extension.
        :param extension_name: cog name without suffix
        """
        if extension_name == Path(__file__).stem:
            await ctx.send(embed=failure(
                "This cog is protected, cannot execute operation."))
            return

        self.bot.reload_extension(f"bot.cogs.{extension_name}")
        await ctx.send(embed=success(f"{extension_name} reloaded.", ctx.me))
示例#20
0
    async def create_mod_mail(self, user: discord.User):
        if user.id in self.pending_mod_mails:
            await user.send(embed=failure("You already have a pending mod mail, please be patient."))
            return

        submission_embed = authored(f"`{user.id}` submitted for mod mail.", author=user)
        # Ping roles so they get notified sooner
        await self.mod_mail_report_channel.send("@here", delete_after=30)
        await self.mod_mail_report_channel.send(embed=submission_embed)

        self.pending_mod_mails.add(user.id)
        await user.send(embed=success("Mod mail was sent to admins, please wait for one of the admins to accept."))
示例#21
0
    async def on_raw_reaction_add(self, payload):
        if payload.channel_id == constants.react_for_roles_channel_id:
            guild = self.bot.get_guild(payload.guild_id)
            member = guild.get_member(payload.user_id)
            role = self.get_assignable_role(payload, guild)

            if member.id == self.bot.user.id:
                return  # Ignore the bot
            elif role is not None:
                await member.add_roles(role)
                embed = success(f"`{role.name}` has been assigned to you in the Tortoise community.")
                await member.send(embed=embed)
示例#22
0
    async def ban(self, ctx, user: GetFetchUser, *, reason="Reason not stated."):
        """Bans  member from the guild."""
        await ctx.guild.ban(user=user, reason=reason)
        await ctx.send(embed=success(f"{user} successfully banned."), delete_after=5)
        deterrence_embed = infraction_embed(ctx, user, constants.Infraction.ban, reason)
        await self.deterrence_log_channel.send(embed=deterrence_embed)

        dm_embed = deterrence_embed
        dm_embed.add_field(
            name="Repeal",
            value="If this happened by a mistake contact moderators."
        )

        await user.send(embed=dm_embed)
示例#23
0
    async def kick(self, ctx, member: discord.Member, *, reason="No specific reason"):
        """Kicks  member from the guild."""
        await member.kick(reason=reason)
        await ctx.send(embed=success(f"{member.name} successfully kicked."), delete_after=5)

        deterrence_embed = infraction_embed(ctx, member, constants.Infraction.kick, reason)
        await self.deterrence_log_channel.send(embed=deterrence_embed)

        dm_embed = deterrence_embed
        dm_embed.add_field(
            name="Repeal",
            value="If this happened by a mistake contact moderators."
        )

        await member.send(embed=dm_embed)
示例#24
0
    async def create_mod_mail(self, user: discord.User):
        if user.id in self.pending_mod_mails:
            await user.send(embed=failure(
                "You already have a pending mod mail, please be patient."))
            return

        mod_mail_report_channel = self.bot.get_channel(
            constants.mod_mail_report_channel_id)
        submission_embed = authored(f"`{user.id}` submitted for mod mail.",
                                    author=user)
        await mod_mail_report_channel.send(embed=submission_embed)
        self.pending_mod_mails.add(user.id)
        await user.send(embed=success(
            "Mod mail was sent to admins, please wait for one of the admins to accept."
        ))
示例#25
0
    async def unload(self, ctx, extension_name):
        """
        Unloads an extension.
        :param extension_name: cog name without suffix
        """
        if extension_name == Path(__file__).stem:
            await ctx.send(embed=failure("This cog is protected, cannot unload."))
            return

        self.bot.unload_extension(f"bot.cogs.{extension_name}")

        msg = f"{extension_name} unloaded."
        logger.info(f"{msg} by {ctx.author.id}")

        await ctx.send(embed=success(f"{extension_name} unloaded.", ctx.me))
示例#26
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))
示例#27
0
    async def mute(self,
                   ctx,
                   member: discord.Member,
                   *,
                   reason="No reason stated."):
        """
        Mutes the member.

        """
        if self.muted_role in member.roles:
            await ctx.send(
                embed=failure("Cannot mute as member is already muted."))
            return

        reason = "Muting member. " + reason

        await member.add_roles(self.muted_role, reason=reason)
        await member.remove_roles(self.verified_role, reason=reason)

        await ctx.send(embed=success(f"{member} successfully muted."),
                       delete_after=5)
示例#28
0
 async def announce(self, ctx, *, arg):
     announcements_channel = self.bot.get_channel(
         constants.announcements_channel_id)
     await announcements_channel.send(arg)
     await ctx.send(success("Announced ✅"))
示例#29
0
    async def attend(self, ctx, user_id: int):
        # Time to wait for FIRST USER reply. Useful if mod attends but user is away.
        first_timeout = 10_800
        # Flag for above variable. False means there has been no messages from the user.
        first_timeout_flag = False
        # After the user sends first reply this is the timeout we use.
        regular_timeout = 600

        user = self.bot.get_user(user_id)
        mod = ctx.author
        # Keep a log of all messages in mod-mail
        log = MessageLogger(mod.id, user.id)
        mod_mail_report_channel = self.bot.get_channel(
            constants.mod_mail_report_channel_id)

        if user is None:
            await ctx.send(embed=failure(
                "That user cannot be found or you entered incorrect ID."))
            return
        elif user_id not in self.pending_mod_mails:
            await ctx.send(
                embed=failure("That user is not registered for mod mail."))
            return
        elif self.is_any_session_active(mod.id):
            await ctx.send(embed=failure(
                "You already have one of active sessions (reports/mod mail etc)."
            ))
            return

        self.pending_mod_mails.remove(user_id)
        self.active_mod_mails[user_id] = mod.id

        await user.send(embed=authored((
            "has accepted your mod mail request.\n"
            "Reply here in DMs to chat with them.\n"
            "This mod mail will be logged, by continuing you agree to that.\n"
            "Type `close` to close this mod mail."),
                                       author=mod))

        await mod.send(
            embed=success(f"You have accepted `{user}` mod mail request.\n"
                          "Reply here in DMs to chat with them.\n"
                          "This mod mail will be logged.\n"
                          "Type `close` to close this mod mail."))
        await ctx.send(embed=success("Mod mail initialized, check your DMs."),
                       delete_after=10)

        def mod_mail_check(msg):
            return msg.guild is None and msg.author.id in (user_id, mod.id)

        _timeout = first_timeout

        while True:
            try:
                mail_msg = await self.bot.wait_for("message",
                                                   check=mod_mail_check,
                                                   timeout=_timeout)
                log.add_message(mail_msg)
            except TimeoutError:
                timeout_embed = failure("Mod mail closed due to inactivity.")
                log.add_embed(timeout_embed)
                await mod.send(embed=timeout_embed)
                await user.send(embed=timeout_embed)
                del self.active_mod_mails[user_id]
                await mod_mail_report_channel.send(file=discord.File(
                    StringIO(str(log)), filename=log.filename))
                break

            # Deal with dynamic timeout.
            if mail_msg.author == user and not first_timeout_flag:
                first_timeout_flag = True
                _timeout = regular_timeout

            # Deal with canceling mod mail
            if mail_msg.content.lower() == "close":
                close_embed = success(
                    f"Mod mail successfully closed by {mail_msg.author}.")
                log.add_embed(close_embed)
                await mod.send(embed=close_embed)
                await user.send(embed=close_embed)
                del self.active_mod_mails[user_id]
                await mod_mail_report_channel.send(file=discord.File(
                    StringIO(str(log)), filename=log.filename))
                break

            # Deal with user-mod communication
            if mail_msg.author == user:
                await mod.send(mail_msg.content)
            elif mail_msg.author == mod:
                await user.send(mail_msg.content)
示例#30
0
 async def welcome(self, ctx, *, arg):
     channel = self.bot.get_channel(constants.welcome_channel_id)
     await channel.send(arg)
     await ctx.send(success("Added in Welcome ✅"))