Beispiel #1
0
    async def invite(self, ctx) -> None:
        """
        Get a link to invite RPANBot to your guild.
        """
        invite_link = "https://discord.com/oauth2/authorize?client_id={client_id}&scope=bot&permissions={invite_permissions}".format(
            client_id=self.bot.core.settings.discord.client_id,
            invite_permissions=self.bot.core.settings.discord.invite_permissions,
        )

        await ctx.send(
            "",
            embed=RPANEmbed(
                title="Click here to invite the bot to your server.",
                description=f"You can also join the [bot support server!]({self.bot.core.settings.links.support_guild})",
                url=invite_link,

                user=ctx.author,
                bot=self.bot,
                message=ctx.message,
            ),
        )
Beispiel #2
0
    async def howtobroadcast(self, ctx) -> None:
        """
        Get information on how to broadcast to RPAN.
        """
        await ctx.send(
            "",
            embed=RPANEmbed(
                title="Click here to view the section on the RPAN wiki.",
                url=
                "https://www.reddit.com/r/pan/wiki/index#wiki_how_do_i_broadcast_on_mobile.3F",
                description=dedent("""
                    There are two ways to broadcast to RPAN: from mobile and from desktop.

                    You can easily broadcast from mobile using the [Reddit app.](https://www.reddit.com/r/pan/wiki/index#wiki_how_do_i_broadcast_on_mobile.3F)

                    To broadcast from desktop, you can use [RPAN Studio.](https://www.reddit.com/r/RPANStudio/comments/hjimlq/you_want_a_desktop_streaming_solution_you_got_it/)
                """).strip(),
                user=ctx.author,
                bot=self.bot,
                message=ctx.message),
        )
Beispiel #3
0
    async def topstreams(self, ctx, time_period: Optional[str] = None) -> None:
        """
        View the top broadcasts on each RPAN subreddit.
        """
        top_broadcasts, time = self.bot.core.strapi.get_top_broadcasts(
            time_period)

        fields = {}
        for subreddit, broadcast in top_broadcasts.items():
            if broadcast is not None:
                fields[
                    f"r/{subreddit}"] = f"[{broadcast.title}]({broadcast.url})"

        await ctx.send(
            "",
            embed=RPANEmbed(
                title="Top Broadcasts",
                description=
                f"The top broadcast on each RPAN subreddit from within: {time}.",
                fields=fields,
                user=ctx.author,
            ))
Beispiel #4
0
    async def developer_restart(self, ctx) -> None:
        """
        DEVELOPER: Restart the bot.
        """
        await ctx.send("",
                       embed=RPANEmbed(
                           title="Development - Restarting Bot",
                           user=ctx.author,
                       ))

        await self.bot.change_presence(status=Status.idle,
                                       activity=Activity(
                                           type=ActivityType.watching,
                                           name="a restart.",
                                       ))

        try:
            await self.bot.logout()
        except Exception:
            pass
        finally:
            print("DEVELOPER: Restarting bot.")
            execl(executable, executable, *argv)
Beispiel #5
0
    async def before_invoke(self, ctx):
        """
        Handles some events before continuing with invoking a command.
        """
        # Handle the global commands cooldown.
        cooldown_bucket = self.spam_cooldown.get_bucket(ctx.message)
        cooldown_retry = cooldown_bucket.update_rate_limit(
            ctx.message.created_at.replace(tzinfo=timezone.utc).timestamp())
        if cooldown_retry:
            # Increment the user's spam counter.
            if ctx.author.id in self.spam_counter:
                self.spam_counter[ctx.author.id] += 1
            else:
                self.spam_counter[ctx.author.id] = 1

            # Load the spam log channel.
            log_channel = await self.bot.find_channel(
                self.bot.core.settings.ids.exclusions_and_spam_channel)

            # Check if the user has been continually spamming.
            if self.spam_counter[ctx.author.id] >= 5:
                self.bot.db_session.add(ExcludedUser(user_id=ctx.author.id))
                self.bot.db_session.commit()
                del self.bot.excluded_user_cache[ctx.author.id]
                del self.spam_counter[ctx.author.id]

                await log_channel.send(
                    "",
                    embed=RPANEmbed(
                        title="Auto Ban Issued",
                        description=
                        "A user has been banned due to the amount of cooldowns they've received.",
                        colour=0x800000,
                        fields={
                            "User":
                            f"{ctx.author} ({ctx.author.id})",
                            "Guild":
                            f"{ctx.guild.name} ({ctx.guild.id})",
                            "Guild Owner":
                            f"{ctx.guild.owner}\n({ctx.guild.owner_id})",
                        },
                    ),
                )
            else:
                await log_channel.send(
                    "",
                    embed=RPANEmbed(
                        title="Spam Note",
                        description="A user has been marked as spamming.",
                        colour=0xFFFF00,
                        fields={
                            "User":
                            f"{ctx.author} ({ctx.author.id})",
                            "Guild":
                            f"{ctx.guild.name} ({ctx.guild.id})",
                            "Guild Owner":
                            f"{ctx.guild.owner}\n({ctx.guild.owner_id})",
                        },
                    ),
                )

            # Raise the exception that the user is on cooldown.
            raise GlobalCooldownFailure
        else:
            if ctx.author.id in self.spam_counter:
                self.spam_counter[ctx.author.id]

        # Start typing before executing the command.
        await ctx.trigger_typing()
Beispiel #6
0
    async def on_command_error(self, ctx, error: Exception) -> None:
        # Ignore if the exception is command not found.
        if isinstance(error, CommandNotFound):
            return

        # Log the exception if it isn't in the exclusion list.
        print(error)
        if self.bot.core.sentry:
            exclusion_list = [
                BadArgument, BotMissingPermissions, CheckFailure,
                ExcludedUserBlocked, MissingPermissions,
                MissingRequiredArgument, GlobalCooldownFailure
            ]
            if not any([
                    isinstance(error, excluded_error)
                    for excluded_error in exclusion_list
            ]):
                self.bot.core.sentry.capture_exception(error)

        # Return if there is already an error handler for this command.
        cmd = ctx.command
        if hasattr(cmd, "on_error"):
            return

        # Don't send error messages for some exceptions.
        if isinstance(error, ExcludedUserBlocked) or isinstance(
                error, GlobalCooldownFailure):
            return

        # Send an error message to other exceptions.
        if isinstance(error, BotMissingPermissions):
            missing_perms = ", ".join(error.missing_perms)
            if "embed_links" not in missing_perms:
                await ctx.send(
                    "",
                    embed=RPANEmbed(
                        title="Missing Permissions",
                        description=
                        f"The bot is missing the following permissions that are required for this command:\n{missing_perms}",
                        colour=0x8B0000,
                    ),
                )
            else:
                await ctx.send(
                    dedent(f"""
                        **Missing Permissions**
                        The bot is missing the following permissions that are required for this command (some required for core functionality):
                        ``{missing_perms}``
                    """), )
        elif isinstance(error, MissingPermissions):
            missing_perms = ", ".join(error.missing_perms)
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="Insufficient Permissions",
                    description=
                    f"You require the following guild permission(s) to use this command: ``{missing_perms}``",
                    colour=0x8B0000,
                ),
            )
        elif isinstance(error, DeveloperCheckFailure):
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="Insufficient Permissions",
                    description=
                    "This command can only be accessed by the bot's core developers.",
                    colour=0x8B0000,
                ),
            )
        elif isinstance(error, CheckFailure):
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="Insufficient Permissions",
                    description="This command cannot run here.",
                    colour=0x8B0000,
                ),
            )
        elif isinstance(error, BadArgument):
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="You've input something wrong.",
                    description=
                    f"The following argument was input incorrectly: '{error.param}'",
                    colour=0x8B0000,
                ),
            )
        elif isinstance(error, MissingRequiredArgument):
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="Missing Argument",
                    description=dedent(f"""
                        A required argument for this command is missing.

                        **Usage:**
                        ``{cmd.name} {cmd.signature}``

                        **Missing Argument:**
                        {error.param.name}

                        **Argument Key**
                        ``[argument]`` optional argument
                        ``<argument>`` required argument
                    """.strip()),
                    colour=0x8B0000,
                    bot=self.bot,
                    message=ctx.message,
                ),
            )
        elif isinstance(error, CommandInvokeError):
            error_log_channel = await self.bot.fetch_channel(
                self.bot.core.settings.ids.error_channel)
            await error_log_channel.send(
                "",
                embed=RPANEmbed(
                    title="Command Error Report",
                    fields={
                        "Error":
                        f"{error.original.__class__.__name__}: {error.original}",
                        "Arguments": "\n".join(error.original.args),
                        "Invoking User": f"{ctx.author} ({ctx.author.id})",
                        "Invoking Message": ctx.message.content,
                        "Guild": f"{ctx.guild.name} ({ctx.guild.id})",
                    },
                    colour=0x8B0000,
                ),
            )
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="An error occurred while executing that command.",
                    description=
                    "But don't worry! A report has been sent to the bot's developers.",
                    colour=0x8B0000,
                    fields={
                        "Support Guild":
                        f"[Click here to join the bot support guild.]({self.bot.core.settings.links.support_guild})",
                    },
                    bot=self.bot,
                    message=ctx.message,
                ),
            )
        else:
            error_log_channel = await self.bot.fetch_channel(
                self.bot.core.settings.ids.error_channel)
            await error_log_channel.send(
                "",
                embed=RPANEmbed(
                    title="Error Report",
                    fields={
                        "Error": f"{error.__class__.__name__}: {error}",
                        "Invoking User": f"{ctx.author} ({ctx.author.id})",
                        "Invoking Message": ctx.message.content,
                        "Guild": f"{ctx.guild.name} ({ctx.guild.id})",
                    },
                    colour=0x8B0000,
                ),
            )
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="Something went wrong.",
                    description=
                    "But don't worry! A report has been sent to the bot's developers.",
                    colour=0x8B0000,
                    fields={
                        "Support Guild":
                        f"[Click here to join the bot support guild.]({self.bot.core.settings.links.support_guild})",
                    },
                    bot=self.bot,
                    message=ctx.message,
                ),
            )
Beispiel #7
0
    async def on_guild_join(self, guild) -> None:
        # Check that the guild isn't banned from the bot.
        is_banned = self.bot.db_session.query(ExcludedGuild).filter_by(
            guild_id=guild.id).first()
        if is_banned:
            self.exclusion_watch = guild.id
            log_channel = await self.bot.find_channel(
                self.bot.core.settings.ids.exclusions_and_spam_channel)
            await log_channel.send(
                "",
                embed=RPANEmbed(
                    title="Excluded Guild Join Attempt",
                    description="A banned guild attempted to add the bot.",
                    fields={
                        "Guild Name": guild.name,
                        "Guild ID": guild.id,
                        "Owner": f"{guild.owner}\n({guild.owner_id})",
                    },
                    thumbnail=guild.icon_url,
                ),
            )

            await guild.leave()
            return

        # Check that the guild owner isn't banned from the bot.
        owner_is_banned = self.bot.db_session.query(ExcludedUser).filter_by(
            user_id=guild.owner_id).first()
        if owner_is_banned:
            self.exclusion_watch = guild.id
            log_channel = await self.bot.find_channel(
                self.bot.core.settings.ids.exclusions_and_spam_channel)
            await log_channel.send(
                "",
                embed=RPANEmbed(
                    title="Excluded User Bot Invite",
                    description=
                    "A banned bot user attempted to add the bot to their guild.",
                    fields={
                        "Guild Name": guild.name,
                        "Guild ID": guild.id,
                        "Owner": f"{guild.owner}\n({guild.owner_id})",
                    },
                    thumbnail=guild.icon_url,
                ),
            )

            await guild.leave()
            return

        # Log that the bot has joined a new guild.
        log_channel = await self.bot.find_channel(
            self.bot.core.settings.ids.join_leave_channel)
        await log_channel.send(
            "",
            embed=RPANEmbed(
                title="Guild Joined",
                description=f"Now in {len(self.bot.guilds)} guilds.",
                colour=0x32CD32,
                fields={
                    "Guild Name": guild.name,
                    "Guild ID": guild.id,
                    "Owner": f"{guild.owner}\n({guild.owner_id})",
                    "Member Count": guild.member_count,
                },
                thumbnail=guild.icon_url,
            ),
        )
Beispiel #8
0
    async def send_bot_help(self, mapping) -> None:
        help_embed = RPANEmbed(
            title="RPANBot Command List",
            description=dedent(f"""
                **Info**
                Type ``{self.clean_prefix}help (command name)`` for more info on a command.
                [Click here to view a more in-depth description of the commands.]({Settings().links.site_base}/commands)

                **Argument Key**
                [argument] | optional argument
                <argument> | required argument
            """.strip()),
            url=Settings().links.site_base + "/commands",
            user=self.context.author,
            bot=self.context.bot,
            message=self.context.message,
        )

        def get_category(command):
            cog = command.cog
            return cog.qualified_name if cog is not None else "None"

        filtered = await self.filter_commands(self.context.bot.commands,
                                              sort=True,
                                              key=get_category)

        category_fields = {}
        for category, commands in groupby(filtered, key=get_category):
            if category == "None":
                continue

            commands = sorted(commands, key=lambda cmd: len(cmd.name))

            category_cmds = ""
            for cmd in commands:
                cmd_line = "\n\n" + cmd.name

                if cmd.signature:
                    cmd_line += " " + cmd.signature

                if cmd.help:
                    cmd_line += ":\n  · " + cmd.help

                category_cmds += cmd_line

            category_fields[category] = self.wrap_listing(category_cmds)

        category_fields = sorted(category_fields.items(),
                                 key=lambda cat: len(cat[1]),
                                 reverse=True)
        for category_info in category_fields:
            help_embed.add_field(
                name=category_info[0],
                value=category_info[1],
                inline=False,
            )

        await self.send_help_message(
            channel=self.get_destination(),
            text="",
            embed=help_embed,
        )
Beispiel #9
0
    async def report(self, ctx, *, type: str = None) -> None:
        """
        Get information on how to report policy breaking content.
        """
        if type is not None:
            type = type.lower()

        report_tables = {
            "promoting hate based on identity or vulnerability":
            "https://www.reddit.com/report?reason=its-promoting-hate-based-on-identity-or-vulnerability",
            "spam":
            "https://www.reddit.com/report?reason=this-is-spam",
            "misinformation":
            "https://www.reddit.com/report?reason=this-is-misinformation",
            "targeted harassment":
            "https://www.reddit.com/report?reason=its-targeted-harassment",
            "violence or physical harm":
            "https://www.reddit.com/report?reason=it-threatens-violence-or-physical-harm",
            "rude, vulgar, or offensive":
            "https://www.reddit.com/report?reason=its-rude-vulgar-or-offensive",
            "abusing the report button":
            "https://www.reddit.com/report?reason=its-abusing-the-report-button",
            "copyright infringements":
            "https://www.reddit.com/report?reason=it-infringes-my-copyright",
            "trademark infringement":
            "https://www.reddit.com/report?reason=it-infringes-my-trademark-rights",
            "personal information":
            "https://www.reddit.com/report?reason=its-personal-and-confidential-information",
            "sexualizing minors":
            "https://www.reddit.com/report?reason=its-sexual-or-suggestive-content-involving-minors",
            "involuntary pornography":
            "https://www.reddit.com/report?reason=its-involuntary-pornography",
            "ban evasion":
            "https://www.reddit.com/report?reason=its-ban-evasion",
            "vote manipulation":
            "https://www.reddit.com/report?reason=its-vote-manipulation",
            "prohibited goods or services":
            "https://www.reddit.com/report?reason=its-a-transaction-for-prohibited-goods-or-services",
            "impersonation":
            "https://www.reddit.com/report?reason=it-impersonates-me",
            "netzdg report":
            "https://www.reddit.com/report?reason=report-this-content-under-netzdg",
            "self-harm or suicide":
            "https://www.reddit.com/report?reason=someone-is-considering-suicide-or-serious-self-harm",
            "appeal a suspension":
            "https://www.reddit.com/appeals",
            "appeal a subreddit ban":
            "https://www.reddit.com/message/compose?to=/r/reddit.com&subject=Subreddit+Ban+Appeal",
            "dmca":
            "https://www.redditinc.com/policies/user-agreement#text-content8",
        }

        if type is not None and type not in report_tables.keys():
            aliases = {
                "rude": "rude, vulgar, or offensive",
                "vulgar": "rude, vulgar, or offensive",
                "offensive": "rude, vulgar, or offensive",
                "copyright infringement": "copyright infringements",
                "copyright": "copyright infringements",
                "trademark": "trademark infringement",
                "dox": "personal information",
                "harassment": "targeted harassment",
                "discrimination":
                "promoting hate based on identity or vulnerability",
                "racism": "promoting hate based on identity or vulnerability",
                "hate": "promoting hate based on identity or vulnerability",
                "self-harm": "self-harm or suicide",
                "netzdg": "netzdg report",
                "violence": "violence or physical harm",
                "harm": "violence or physical harm",
            }

            if type in aliases.keys():
                type = aliases[type]

        embed = RPANEmbed(
            title="Click here to go to the report page.",
            description=dedent("""
                If you need to report a user, comment, or post, please go to https://reddit.com/report (or click above) and report the content there.

                If you cannot find a category for the content you want to report, then [send a message to r/reddit.com](https://reddit.com/message/compose/?to=/r/reddit.com) with the content.
            """.strip()),
            url="https://reddit.com/report",
            user=ctx.author,
        )

        if type in report_tables.keys():
            embed.url = report_tables[type]
            embed.description = dedent("""
                Visit the following link (or click above) to report for '{type}':
                {link}
            """.strip()).format(type=type.capitalize(), link=embed.url)

        await ctx.send("", embed=embed)
Beispiel #10
0
    async def viewstream(self, ctx, username: str) -> None:
        """
        Get the current or last stream of a specified user.
        """
        broadcasts = self.bot.core.strapi.get_broadcasts()
        if broadcasts is None:
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title="View Stream",
                    description=
                    "There was a problem with fetching the broadcasts, please try again later.",
                    colour=0xD2D219,
                    user=ctx.author,
                    bot=self.bot,
                    message=ctx.message),
            )
            return

        broadcast = broadcasts.has_streamer(name=username)
        if broadcast:
            await ctx.send(
                "",
                embed=RPANEmbed(
                    title=
                    f"u/{broadcast.author_name}'s Current Broadcast (Live)",
                    fields={
                        "Title": broadcast.title,
                        "Author": f"u/{broadcast.author_name}",
                        "Subreddit": f"r/{broadcast.subreddit_name}",
                        "RPAN Rank":
                        f"{broadcast.global_rank}/{broadcast.total_streams}",
                        "Current Viewers": broadcast.continuous_watchers,
                        "Unique Viewers": broadcast.unique_watchers,
                    },
                    url=broadcast.url,
                    thumbnail=broadcast.thumbnail,
                    user=ctx.author,
                    bot=self.bot,
                    message=ctx.message,
                ),
            )
        else:
            broadcast = self.bot.core.strapi.get_last_broadcast(username)
            if broadcast:
                await ctx.send(
                    "",
                    embed=RPANEmbed(
                        title=f"u/{broadcast.author_name}'s Last Broadcast",
                        fields={
                            "Title":
                            broadcast.title,
                            "Author":
                            f"u/{broadcast.author_name}",
                            "Subreddit":
                            f"r/{broadcast.subreddit_name}",
                            "Status":
                            "Off-Air",
                            "Broadcasted":
                            self.bot.core.strapi.format_broadcast_timestamp(
                                broadcast.published_at).strftime(
                                    "%d/%m/%Y at %H:%M UTC"),
                            "Unique Viewers":
                            broadcast.unique_watchers,
                        },
                        url=broadcast.url,
                        thumbnail=broadcast.thumbnail,
                        user=ctx.author,
                        bot=self.bot,
                        message=ctx.message,
                    ),
                )
            else:
                await ctx.send("No last broadcast was found for that user.")