Ejemplo n.º 1
0
    async def convert(self, ctx: context.CustomContext, argument):
        if not ctx.bot.mk.NATION_ROLE_PREFIX:
            raise exceptions.DemocracivBotException(
                f"{config.NO} You can't use Nation Roles with this bot.")

        arg = argument.lower()
        prefix = ctx.bot.mk.NATION_ROLE_PREFIX.lower()

        if arg.startswith(prefix):
            real_arg = arg

        elif arg.startswith(prefix[:-2]):
            real_arg = arg.replace(prefix[:-2], prefix)

        else:
            real_arg = f"{ctx.bot.mk.NATION_ROLE_PREFIX}{argument}"

        role = await super().convert(ctx, real_arg)

        if not role.name.lower().startswith(
                ctx.bot.mk.NATION_ROLE_PREFIX.lower()):
            raise commands.BadArgument(
                f"{config.NO} You're not allowed to give someone the `{role.name}` role."
            )

        return role
Ejemplo n.º 2
0
    async def pin(self, ctx, *, message: discord.Message = None):
        """Pin a message

        You can either reply to the message you want me to pin, or give me the message's ID like shown below.

        **Example**
            `{PREFIX}{COMMAND} 784598328666619934` use the message's ID *(only works if you use the command in the same channel as the message you want to pin)*
            `{PREFIX}{COMMAND} https://discord.com/channels/208984105310879744/499669824847478785/784598328666619934` use the message's URL

        """
        if not message and ctx.message.reference:
            message = ctx.message.reference.resolved

            if not message:
                message = await ctx.channel.fetch_message(
                    ctx.message.reference.message_id)

                if not message:
                    return

        if message.channel.category_id not in self.bot.mk.NATION_CATEGORIES:
            raise exceptions.DemocracivBotException(
                f"{config.NO} You're not allowed to pin messages in this channel."
            )

        await message.pin()
Ejemplo n.º 3
0
    async def _search_model(self, ctx, *, model, query: str, return_model=False):
        if len(query) < 3:
            raise exceptions.DemocracivBotException(
                f"{config.NO} The query to search for has to be at least 3 characters long."
            )

        if model is models.Motion:
            found = await self.bot.db.fetch(
                "SELECT id from motion WHERE (lower(title) LIKE '%' || $1 || '%') OR"
                " (lower(description) LIKE '%' || $1 || '%') "
                "ORDER BY similarity(lower(title), $1) DESC LIMIT 20",
                query.lower(),
            )
            formatted = []

            for record in found:
                obj = await model.convert(ctx, record["id"])
                if return_model:
                    formatted.append(obj)
                else:
                    formatted.append(obj.formatted)
        else:
            is_law = model is models.Law
            # First, search by name similarity
            async with self.bot.db.acquire() as con:
                results = await self._search_bill_by_name(
                    query, connection=con, search_laws=is_law, return_model=return_model
                )

                # Set word similarity threshold for search by tag
                await self._update_pg_trgm_similarity_threshold(0.4, connection=con)

                # Then, search by tag similarity
                # for word in query.split():
                #    if len(word) < 3 or word in (
                #        "the",
                #        "author",
                #        "authors",
                #        "date",
                #        "name",
                #        "and",
                #        "d/m/y",
                #        "type",
                #        "description",
                #        "by",
                #        "generated",
                #    ):
                #        continue

                result = await self._search_bill_by_tag(
                    query, connection=con, search_laws=is_law, return_model=return_model
                )
                if result:
                    results.update(result)

            formatted = list(results)

        return formatted
Ejemplo n.º 4
0
    async def tinyurl(self, url: str) -> typing.Optional[str]:
        async with self.session.post(
                f"https://api.shrtco.de/v2/shorten?url={url}") as response:
            if response.status in (200, 201):
                tiny_url = await response.json()

                try:
                    return tiny_url["result"]["full_short_link"]
                except KeyError:
                    raise exceptions.DemocracivBotException(
                        f"{config.NO} The URL shortening service returned an error, try again later."
                    )
Ejemplo n.º 5
0
    async def check(ctx):
        if ctx.author.id == ctx.bot.owner_id:
            return True

        is_allowed = (
            ctx.author.guild_permissions.administrator
            or await ctx.bot.get_guild_setting(ctx.guild.id, "tag_creation_allowed")
        )

        if is_allowed:
            return True
        else:
            raise exceptions.DemocracivBotException(
                message=f"{config.NO} Only Administrators can add or remove tags on this server."
                " Administrators can change this setting in "
                f"`{config.BOT_PREFIX}server tagcreation`."
            )
Ejemplo n.º 6
0
 def wrapper(ctx):
     if not ctx.bot.mk.NATION_ROLE_PREFIX:
         raise exceptions.DemocracivBotException(
             f"{config.NO} You can't use Nation Roles with this bot.")
     else:
         return True
Ejemplo n.º 7
0
    async def create_new_party(
        self,
        ctx: CustomContext,
        *,
        role=True,
        leaders=True,
        invite=True,
        join_mode=True,
        commit=True,
        merge=False,
    ) -> typing.Union[typing.Dict, PoliticalParty]:

        result = {
            "role": None,
            "invite": None,
            "leaders": [],
            "join_mode": None
        }

        if role:
            await ctx.send(
                f"{config.USER_INTERACTION_REQUIRED} Reply with the name of the new party you want to create."
            )

            role_name = await ctx.converted_input(
                converter=converter.CaseInsensitiveRole)

            if isinstance(role_name, str):
                await ctx.send(
                    f"{config.YES} I will **create a new role** on this server named `{role_name}`"
                    f" for the new party.")
                try:
                    discord_role = await ctx.guild.create_role(name=role_name)
                except discord.Forbidden:
                    raise exceptions.ForbiddenError(
                        exceptions.ForbiddenTask.CREATE_ROLE, role_name)

            else:
                discord_role = role_name

                try:
                    match = await PoliticalParty.convert(ctx, role_name)

                    if match and merge:
                        await ctx.send(
                            f"{config.YES} I'll use the **already existing** party `{discord_role.name}` to merge "
                            f"the others into.")
                        return match

                except exceptions.NotFoundError:
                    pass

                await ctx.send(
                    f"{config.YES} I'll use the **pre-existing role** `{discord_role.name}` for the new party."
                )

            result["role"] = discord_role

        if leaders:
            img = await self.bot.make_file_from_image_link(
                "https://cdn.discordapp.com/attachments/499669824847478785/784584955921301554/partyjoin.PNG"
            )

            await ctx.send(
                f"{config.USER_INTERACTION_REQUIRED} Reply with the names or mentions of the party's leaders or "
                f"representatives. If this party has multiple leaders, separate them with a newline, like in the "
                f"image below.\n\n "
                f"{config.HINT} *Party leaders get DM notifications by me when someone joins or leaves their "
                f"party, and they are the ones that can accept and deny join requests if the party's join mode "
                f"is request-based.*",
                file=img,
            )

            leaders_text = (await ctx.input()).splitlines()

            leaders = []

            conv = Fuzzy[converter.CaseInsensitiveMember]

            for leader in leaders_text:
                try:
                    converted = await conv.convert(ctx, leader.strip())

                    if not converted.bot:
                        leaders.append(converted.id)

                except commands.BadArgument:
                    continue

            if not leaders:
                leaders.append(0)

            result["leaders"] = leaders

        if invite:
            party_invite = await ctx.input(
                f"{config.USER_INTERACTION_REQUIRED} Reply with the invite link to the party's Discord server. "
                f"If they don't have one, just reply with gibberish.")

            if not self.discord_invite_pattern.fullmatch(party_invite):
                party_invite = "None"

            result["invite"] = party_invite

        if join_mode:
            view = SelectJoinModeView(ctx)

            await ctx.send(
                f"{config.USER_INTERACTION_REQUIRED} Should this party be public, request-based, or private?",
                view=view,
            )

            join_mode = await view.prompt()
            result["join_mode"] = join_mode

        if commit:
            async with self.bot.db.acquire() as connection:

                if result["invite"] == "None":
                    result["invite"] = None

                async with connection.transaction():
                    try:
                        await connection.execute(
                            "INSERT INTO party (id, discord_invite, join_mode) VALUES ($1, $2, $3)"
                            "ON CONFLICT (id) DO UPDATE SET discord_invite = $2, join_mode = $3 WHERE party.id = $1",
                            result["role"].id,
                            result["invite"],
                            result["join_mode"],
                        )
                    except asyncpg.UniqueViolationError:
                        raise exceptions.DemocracivBotException(
                            f"{config.NO} `{result['role'].name}` already is a "
                            f"political party. If you "
                            f"want to edit it, use `{config.BOT_PREFIX}party edit "
                            f"{result['role'].name}` "
                            f"instead. ")

                    await connection.execute(
                        "INSERT INTO party_alias (party_id, alias) VALUES ($1, $2) ON CONFLICT DO NOTHING ",
                        result["role"].id,
                        result["role"].name.lower(),
                    )

                    for leader in result["leaders"]:
                        await connection.execute(
                            "INSERT INTO party_leader (party_id, leader_id) VALUES ($1, $2) ON CONFLICT DO NOTHING ",
                            result["role"].id,
                            leader,
                        )

                return await PoliticalParty.convert(ctx, result["role"].id)

        return result