Example #1
0
    async def __main__(self, ExtensionArgs):
        user   = ExtensionArgs.resolved
        guild  = ExtensionArgs.guild
        author = ExtensionArgs.author

        response = ExtensionArgs.response

        if user.bot:
            raise Error("Bots cannot have Roblox accounts!", hidden=True)

        try:
            roblox_user, _  = await get_user(user=user, guild=guild, cache=True, includes=True)
        except RobloxNotFound:
            raise Error("This Roblox account doesn't exist.")
        except RobloxAPIError:
            raise Error("The Roblox API appears to be down so I was unable to retrieve the information. Please try again later.")
        except UserNotVerified:
            raise Error("This user is not linked to Bloxlink!")
        else:
            author_accounts = await get_accounts(author)

            card = Card(user, author, author_accounts, roblox_user, "getinfo", guild, from_interaction=True)
            await card()

            card.response = response

            message = await response.send(files=[card.front_card_file], view=card.view)

            card.message = message
            card.view.message = message
Example #2
0
    async def validate_items(message, content):
        items = content.replace(" ", "").split(",")[:3]
        favorite_items = set()

        for item in items:
            item_id = catalog_id_regex.search(item)

            if item_id:
                item_id = item_id.group(1)
            else:
                item_id = item

                if not item_id.isdigit():
                    raise Error(
                        f"Unable to resolve `{item_id}` into a **Catalog Item ID.**"
                    )

                try:
                    item = await get_catalog_item(item_id)
                except RobloxNotFound:
                    raise Error(
                        f"Unable to resolve `{item_id}` into a **Catalog Item ID.**"
                    )

            favorite_items.add(item_id)

        return favorite_items
Example #3
0
    async def __main__(self, CommandArgs):
        author = CommandArgs.author
        guild = CommandArgs.guild
        transfer_to = CommandArgs.parsed_args.get("user")
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        if transfer_to.bot:
            raise Message("You cannot transfer your premium to bots!", type="confused")

        author_data = await self.r.db("bloxlink").table("users").get(str(author.id)).run() or {"id": str(author.id)}

        time_now = time.time()

        author_premium_data = author_data.get("premium", {})

        transfer_cooldown = author_premium_data.get("transferCooldown") or 0
        on_cooldown = transfer_cooldown > time_now

        if on_cooldown:
            days_left = math.ceil((transfer_cooldown - time_now)/86400)

            raise Message(f"You recently transferred your premium! You may transfer again in **{days_left}** day{days_left > 1 and 's' or ''}.", type="silly")

        if author_premium_data.get("transferTo"):
            raise Message(f"You are currently transferring your premium to another user! Please disable it with `{prefix}transfer "
                           "disable` first.", type="info")
        elif author_premium_data.get("transferFrom"):
            raise Message("You may not transfer premium that someone else transferred to you. You must first revoke the transfer "
                         f"with `{prefix}transfer disable`.", type="confused")

        prem_data, _ = await get_features(author, author_data=author_data, cache=False, rec=False, partner_check=False)

        if not prem_data.features.get("premium"):
            raise Error("You must have premium in order to transfer it!")

        recipient_data = await self.r.db("bloxlink").table("users").get(str(transfer_to.id)).run() or {}
        recipient_data_premium = recipient_data.get("premium", {})

        if recipient_data_premium.get("transferFrom"):
            raise Error(f"Another user is already forwarding their premium to this user. The recipient must run `{prefix}transfer disable` "
                        "to revoke the external transfer.")

        await CommandArgs.prompt([{
            "prompt": f"Are you sure you want to transfer your premium to **{transfer_to}**?\n"
                      "You will not be able transfer again for **5** days! We also do __not__ "
                      "remove cool-downs for __any reason at all.__\n\nYou will be "
                      f"able to cancel the transfer at anytime with `{prefix}transfer disable`.",
            "footer": "Please say **yes** to complete the transfer.",
            "type": "choice",
            "choices": ("yes",),
            "name": "_",
            "embed_title": "Premium Transfer Confirmation",
            "embed_color": BROWN_COLOR,
            "formatting": False
        }])

        await transfer_premium(transfer_from=author, transfer_to=transfer_to, guild=guild, apply_cooldown=True)

        await response.success(f"Successfully **transferred** your premium to **{transfer_to}!**")
Example #4
0
    async def __main__(self, CommandArgs):
        target = CommandArgs.parsed_args["target"] or CommandArgs.message.author
        flags = CommandArgs.flags
        guild = CommandArgs.message.guild
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        if target.bot:
            raise Message("Bots can't have Roblox accounts!", type="silly")

        valid_flags = ["username", "id", "avatar", "premium", "badges", "groups", "description", "age", "banned"]

        if not all(f in valid_flags for f in flags.keys()):
            raise Error(f"Invalid flag! Valid flags are: ``{', '.join(valid_flags)}``")

        #async with response.loading():
        if guild:
            role_binds, group_ids, _ = await get_binds(guild_data=CommandArgs.guild_data, trello_board=CommandArgs.trello_board)
        else:
            role_binds, group_ids = {}, {}

        try:
            account, accounts = await get_user(*flags.keys(), author=target, guild=guild, group_ids=(group_ids, role_binds), send_embed=True, response=response, everything=not bool(flags), basic_details=not bool(flags))
        except UserNotVerified:
            raise Error(f"**{target}** is not linked to Bloxlink.")
        else:
            if not account:
                raise Message(f"You have no primary account set! Please use ``{prefix}switchuser`` and set one.", type="silly")
Example #5
0
    async def validate_games(message, content):
        games = content.replace(" ", "").split(",")[:3]
        favorite_games = set()

        for game in games:
            game_id = game_id_regex.search(game)

            if game_id:
                game_id = game_id.group(1)
            else:
                game_id = game

                if not game_id.isdigit():
                    raise Error(
                        f"Unable to resolve `{game_id}` into a **Game ID.**")

                try:
                    game = await get_game(game_id)
                except RobloxNotFound:
                    raise Error(
                        f"Unable to resolve `{game_id}` into a **Game ID.**")

            favorite_games.add(game_id)

        return favorite_games
Example #6
0
    async def __main__(self, CommandArgs):
        response = CommandArgs.response
        guild = CommandArgs.guild
        author = CommandArgs.author

        roblox_info = CommandArgs.parsed_args["roblox_name"]
        discord_user = CommandArgs.parsed_args["discord_user"]

        roblox_id = roblox_name = None

        if roblox_info and discord_user:
            raise Message(
                "Please only specify a Roblox username OR a Discord user!",
                type="silly")

        elif not (roblox_info or discord_user):
            discord_user = CommandArgs.author

        if roblox_info:
            roblox_id = self.autocomplete_regex.search(roblox_info)

            if not roblox_id:
                roblox_name = roblox_info
            else:
                roblox_id = roblox_id.group(1)

        try:
            roblox_user, _ = await get_user(user=discord_user,
                                            roblox_id=roblox_id,
                                            roblox_name=roblox_name,
                                            guild=guild,
                                            cache=True,
                                            includes=True)
        except RobloxNotFound:
            raise Error("This Roblox account doesn't exist.")
        except RobloxAPIError:
            raise Error(
                "The Roblox API appears to be down so I was unable to retrieve the information. Please try again later."
            )
        except UserNotVerified:
            raise Error("This user is not linked to Bloxlink!")
        else:
            author_accounts = await get_accounts(author)

            card = Card(discord_user or author,
                        author,
                        author_accounts,
                        roblox_user,
                        "getinfo",
                        guild,
                        from_interaction=True)
            await card()

            card.response = response

            message = await response.send(files=[card.front_card_file],
                                          view=card.view)

            card.message = message
            card.view.message = message
Example #7
0
    async def __main__(self, CommandArgs):
        response = CommandArgs.response
        message  = CommandArgs.message
        author   = CommandArgs.author
        guild    = CommandArgs.guild
        prefix   = CommandArgs.prefix
        user     = CommandArgs.parsed_args["user"] or author

        trello_board = CommandArgs.trello_board
        guild_data = CommandArgs.guild_data

        inactive_role = await get_inactive_role(guild, guild_data, trello_board)

        #async with response.loading():
        try:
            roblox_user, _ = await get_user(author=user, guild=guild)
        except UserNotVerified:
            if user == author:
                if message:
                    message.content = f"{CommandArgs.prefix}verify"
                    return await parse_message(message)
                else:
                    raise Error(f"You're not linked to Bloxlink! Please run `{prefix}verify add`.")
            else:
                raise Error(f"**{user}** is not linked to Bloxlink.")
        else:
            embed = await get_profile(author=author, user=user, roblox_user=roblox_user, prefix=prefix, inactive_role=inactive_role, guild=guild, guild_data=guild_data)

            await response.send(embed=embed)
Example #8
0
    async def __main__(self, ExtensionArgs):
        user = ExtensionArgs.resolved
        guild = ExtensionArgs.guild

        guild_data = ExtensionArgs.guild_data
        response = ExtensionArgs.response
        prefix = ExtensionArgs.prefix

        if user.bot:
            raise Error("Bots cannot have Roblox accounts!", hidden=True)

        if guild:
            role_binds, group_ids, _ = await get_binds(guild_data=guild_data)
        else:
            role_binds, group_ids = {}, {}

        try:
            account, accounts = await get_user(author=user,
                                               guild=guild,
                                               group_ids=(group_ids,
                                                          role_binds),
                                               send_embed=True,
                                               send_ephemeral=True,
                                               response=response,
                                               everything=True)
        except UserNotVerified:
            raise Error(f"**{user}** is not linked to Bloxlink.", hidden=True)
        else:
            if not account:
                raise Message(
                    f"This Discord user has no primary account set! They may use `{prefix}switchuser` to set one.",
                    type="info",
                    hidden=True)
Example #9
0
    async def __main__(self, CommandArgs):
        trello_board = CommandArgs.trello_board
        guild_data = CommandArgs.guild_data
        guild = CommandArgs.guild
        author = CommandArgs.author
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        trello_options = {}

        if trello_board:
            trello_options, _ = await get_options(trello_board)
            guild_data.update(trello_options)

        try:
            old_nickname = author.display_name

            added, removed, nickname, errors, warnings, roblox_user = await guild_obligations(
                author,
                guild                = guild,
                guild_data           = guild_data,
                join                 = True,
                roles                = True,
                nickname             = True,
                trello_board         = CommandArgs.trello_board,
                cache                = False,
                response             = response,
                dm                   = False,
                exceptions           = ("BloxlinkBypass", "Blacklisted", "UserNotVerified", "PermissionError", "RobloxDown", "RobloxAPIError")
            )

        except BloxlinkBypass:
            raise Message("Since you have the `Bloxlink Bypass` role, I was unable to update your roles/nickname.", type="info")

        except Blacklisted as b:
            if isinstance(b.message, str):
                raise Error(f"{author.mention} has an active restriction for: `{b}`")
            else:
                raise Error(f"{author.mention} has an active restriction from Bloxlink.")

        except UserNotVerified:
            view = discord.ui.View()
            view.add_item(item=discord.ui.Button(style=discord.ButtonStyle.link, label="Verify with Bloxlink", url=VERIFY_URL, emoji="🔗"))
            view.add_item(item=discord.ui.Button(style=discord.ButtonStyle.link, label="Stuck? See a Tutorial", emoji="❔",
                                                 url="https://www.youtube.com/watch?v=0SH3n8rY9Fg&list=PLz7SOP-guESE1V6ywCCLc1IQWiLURSvBE&index=2"))

            await response.send("To verify with Bloxlink, click the link below.", mention_author=True, view=view)

        except PermissionError as e:
            raise Error(e.message)

        else:
            welcome_message, embed, view = await format_update_embed(roblox_user, author, added=added, removed=removed, errors=errors, warnings=warnings, nickname=nickname if old_nickname != nickname else None, prefix=prefix, guild_data=guild_data)

            await post_event(guild, guild_data, "verification", f"{author.mention} ({author.id}) has **verified** as `{roblox_user.username}`.", GREEN_COLOR)

            await response.send(content=welcome_message, embed=embed, view=view, mention_author=True)
Example #10
0
    async def lookup(self, CommandArgs):
        """lookup a case by its ID"""

        case_id = (await CommandArgs.prompt([
            {
                "prompt": "Please provide a Case ID.",
                "name": "case_id"
            }
        ], last=True))["case_id"]

        response = CommandArgs.response
        prefix   = CommandArgs.prefix

        guild   = CommandArgs.message.guild

        addon_data = await self.r.table("addonData").get(str(guild.id)).run() or {"id": str(guild.id)}
        court_data = addon_data.get("court") or {}
        cases = court_data.get("cases") or {}


        if not court_data:
            raise Error(f"You must set-up this add-on before you can use it! Please use ``{prefix}courtsetup`` "
                        "to begin the set-up.")
        elif not cases:
            raise Error(f"This server has no active cases! Cases may be created with ``{prefix}case create``.")


        for channel_id, case in cases.items():
            if case["caseID"] == case_id:
                break
        else:
            raise Error("I was unable to find the selected case! It may have already been closed.")

        group_members_ = case.get("groupMembers", {})
        group_members_str = "None"

        if group_members_:
            group_members_str = []

            for group, group_members in group_members_.items():
                group_members_str.append(f"**{group}** {ARROW} {', '.join([f'<@{m}>' for m in group_members])}")

            group_members_str = "\n".join(group_members_str)


        embed = Embed(title=f"Case {case['caseName']}")

        embed.add_field(name="Case ID", value=case_id)
        embed.add_field(name="Presiding Judge", value=f"<@{case['presidingJudge']}>")
        embed.add_field(name="Case Channel", value=f"<#{channel_id}>")
        embed.add_field(name="Group Members", value=group_members_str, inline=False)

        await response.send(embed=embed)
Example #11
0
    async def unmute(self, CommandArgs):
        """unmute case members"""

        response = CommandArgs.response
        prefix   = CommandArgs.prefix

        guild   = CommandArgs.message.guild
        channel = CommandArgs.message.channel
        author  = CommandArgs.message.author

        addon_data = await self.r.table("addonData").get(str(guild.id)).run() or {"id": str(guild.id)}
        court_data = addon_data.get("court") or {}
        groups     = court_data.get("groups") or []

        current_case = court_data.get("cases", {}).get(str(channel.id))

        if not current_case:
            raise Error("You must run this command in a case channel!")

        elif int(current_case["presidingJudge"]) != author.id:
            raise Error("You must be the presiding judge in order to run this command!")

        elif not groups:
            raise Error("You need at least one group in order to run this command!") # TODO: add instructions on creating groups

        parsed_args = await CommandArgs.prompt([
            {
                "prompt": f"Which group should be muted? Available groups: ``{groups}``",
                "name": "group",
                "type": "choice",
                "choices": groups,
                "formatting": False
            }
        ], last=True)

        group = parsed_args["group"]
        group_members = current_case["groupMembers"].get(group) or []

        if not group_members:
            raise Error(f"This group has no members associated with it! Please add them with ``{prefix}case add``")

        if not guild.chunked:
            await guild.chunk()

        for member_id in group_members:
            member = guild.get_member(int(member_id))

            if member:
                await channel.set_permissions(member, read_messages=True, send_messages=True)


        await response.success(f"Successfully **unmuted** the members from group ``{group}``!")
Example #12
0
    async def __main__(self, CommandArgs):
        target = CommandArgs.parsed_args["roblox_name"]
        flags = CommandArgs.flags
        response = CommandArgs.response
        message = CommandArgs.message
        guild = CommandArgs.guild
        prefix = CommandArgs.prefix

        if message and message.mentions and CommandArgs.string_args:
            message.content = f"{prefix}getinfo {CommandArgs.string_args[0]}"
            return await parse_message(message)

        valid_flags = ["username", "id", "avatar", "premium", "badges", "groups", "description", "age", "banned", "devforum"]

        if not all(f in valid_flags for f in flags.keys()):
            raise Error(f"Invalid flag! Valid flags are: `{', '.join(valid_flags)}`")

        username = ID = False

        if "username" in flags:
            username = True
            flags.pop("username")
        elif target.isdigit():
            ID = True
        else:
            username = True

        #async with response.loading():
        if guild:
            role_binds, group_ids, _ = await get_binds(guild_data=CommandArgs.guild_data, trello_board=CommandArgs.trello_board)
        else:
            role_binds, group_ids = {}, {}

        try:
            _, _ = await get_user(*flags.keys(), username=username and target, roblox_id=ID and target, group_ids=(group_ids, role_binds), send_embed=True, guild=guild, response=response, everything=not bool(flags), basic_details=not bool(flags))
        except RobloxNotFound:
            raise Error("This Roblox account doesn't exist.")
        except RobloxAPIError:
            if ID:
                try:
                    await Bloxlink.fetch_user(int(target))
                except NotFound:
                    raise Error("This Roblox account doesn't exist.")
                else:
                    if message:
                        message.content = f"{prefix}getinfo {target}"
                        return await parse_message(message)
                    else:
                        raise Message(f"To search with Discord IDs, please use the `{prefix}getinfo` command.\n"
                                      "This command only searches by Roblox username or ID.", hidden=True, type="info")
            else:
                raise Error("This Roblox account doesn't exist.")
Example #13
0
    async def __main__(self, CommandArgs):
        trello_board = CommandArgs.trello_board
        guild_data = CommandArgs.guild_data
        guild = CommandArgs.guild
        author = CommandArgs.author
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        trello_options = {}

        if trello_board:
            trello_options, _ = await get_options(trello_board)
            guild_data.update(trello_options)

        try:
            old_nickname = author.display_name

            added, removed, nickname, errors, warnings, roblox_user = await guild_obligations(
                author,
                guild                = guild,
                guild_data           = guild_data,
                roles                = True,
                nickname             = True,
                trello_board         = CommandArgs.trello_board,
                cache                = False,
                response             = response,
                dm                   = False,
                exceptions           = ("BloxlinkBypass", "Blacklisted", "UserNotVerified", "PermissionError", "RobloxDown", "RobloxAPIError")
            )

        except BloxlinkBypass:
            raise Message("Since you have the `Bloxlink Bypass` role, I was unable to update your roles/nickname.", type="info")

        except Blacklisted as b:
            if isinstance(b.message, str):
                raise Error(f"{author.mention} has an active restriction for: `{b}`")
            else:
                raise Error(f"{author.mention} has an active restriction from Bloxlink.")

        except UserNotVerified:
            await response.reply("To verify with Bloxlink, please visit our website at "
                                f"<{VERIFY_URL}>. It won't take long!\nStuck? See this video: <https://www.youtube.com/watch?v=hq496NmQ9GU>", hidden=True)

        except PermissionError as e:
            raise Error(e.message)

        else:
            welcome_message, embed = await format_update_embed(roblox_user, author, added=added, removed=removed, errors=errors, warnings=warnings, nickname=nickname if old_nickname != author.display_name else None, prefix=prefix, guild_data=guild_data)

            await post_event(guild, guild_data, "verification", f"{author.mention} ({author.id}) has **verified** as `{roblox_user.username}`.", GREEN_COLOR)

            await response.send(content=welcome_message, embed=embed)
Example #14
0
    async def cleanup(self, CommandArgs):
        """free old cases from the database"""

        guild    = CommandArgs.message.guild
        author   = CommandArgs.message.author
        prefix   = CommandArgs.prefix
        response = CommandArgs.response

        addon_data = await self.r.table("addonData").get(str(guild.id)).run() or {"id": str(guild.id)}
        court_data = addon_data.get("court") or {}
        cases = court_data.get("cases") or {}

        removed = 0

        my_permissions = guild.me.guild_permissions

        if not (my_permissions.manage_channels and my_permissions.manage_roles):
            raise Error("I need both the ``Manage Channels`` and ``Manage Roles`` permissions.")

        elif not court_data:
            raise Error(f"You must set-up this add-on before you can use it! Please use ``{prefix}courtsetup`` "
                        "to begin the set-up.")

        elif not cases:
            raise Message("Cannot clean cases: you have no cases saved to the database.", type="silly")


        for judge_role_id in court_data.get("judgeRoles", []):
            if find(lambda r: r.id == int(judge_role_id), author.roles):
                break
        else:
            raise Error("You must have a Judge role in order to run this command!")

        for channel_id, case in dict(cases).items():
            case_channel = guild.get_channel(int(channel_id))

            if not case_channel or (case_channel and case_channel.category and case_channel.category.id != case["archiveCategory"]):
                cases.pop(channel_id)
                removed += 1


        court_data["cases"] = cases
        addon_data["court"] = court_data

        await self.r.table("addonData").insert(addon_data, conflict="replace").run()

        if removed:
            await response.success(f"Successfully removed **{removed}** old case(s) from the database.")
        else:
            await response.silly("No cases to clean: all case channels still exist in your server.")
Example #15
0
    async def remove(self, CommandArgs):
        """allow a user or group back in your server"""

        guild    = CommandArgs.guild
        response = CommandArgs.response

        restrictions = await get_guild_value(guild, "restrictions") or {}

        remove_data = CommandArgs.parsed_args["restriction_data"]
        remove_data_match = self._remove_data_regex.search(remove_data)

        if not remove_data_match:
            raise Message("You must select an option from the dropdown!", type="silly")
        else:
            directory_name, remove_id = remove_data_match.group(1), remove_data_match.group(2)

        if directory_name and remove_id:
            if restrictions.get(directory_name, {}).get(remove_id):
                restrictions[directory_name].pop(remove_id)

                if not restrictions[directory_name]:
                    restrictions.pop(directory_name, None)

                if not restrictions:
                    restrictions = None

                await set_guild_value(guild, restrictions=restrictions)

                await response.success(f"Successfully **removed** this **{directory_name[:-1]}** from your restrictions.")

            else:
                raise Error(f"This **{directory_name[:-1]}** isn't restricted!")
Example #16
0
    async def __main__(self, CommandArgs):
        response = CommandArgs.response

        author = CommandArgs.message.author
        guild = CommandArgs.message.guild

        guild_data = CommandArgs.guild_data
        disabled_commands = guild_data.get("disabledCommands", {})

        disable_type = CommandArgs.parsed_args["disable_type"]
        command_name = CommandArgs.parsed_args["command_name"]

        if command_name in ("disable",
                            "enable") or commands[command_name].developer_only:
            raise Error("You can't disable this command!")

        enable = disable_where = ""

        if isinstance(disable_type, TextChannel):
            channel_id = str(disable_type.id)
            disabled_commands["channels"] = disabled_commands.get(
                "channels", {})

            disable_where = f"for channel {disable_type.mention}"

            if disabled_commands["channels"].get(channel_id):
                disabled_commands["channels"].pop(channel_id)
                enable = "enabled"
            else:
                disabled_commands["channels"][channel_id] = command_name
                enable = "disabled"

        else:
            disabled_commands["global"] = disabled_commands.get("global", [])

            disable_where = "**globally**"

            if command_name in disabled_commands["global"]:
                disabled_commands["global"].remove(command_name)
                enable = "enabled"
            else:
                disabled_commands["global"].append(command_name)
                enable = "disabled"

        guild_data["disabledCommands"] = disabled_commands
        await self.r.table("guilds").insert(guild_data,
                                            conflict="replace").run()

        await set_guild_value(guild, "disabledCommands", disabled_commands)

        await response.success(
            f"Successfully **{enable}** command ``{command_name}`` {disable_where} for non-admins.\n"
            "If you would like to grant a certain person access to use this command, give them a role called ``Bloxlink Bypass``."
        )

        await post_event(
            guild, guild_data, "configuration",
            f"{author.mention} ({author.id}) has **{enable}** the command ``{command_name}`` {disable_where}.",
            BROWN_COLOR)
Example #17
0
        async def validate(message, content):
            try:
                await trello_board.sync(card_limit=TRELLO["CARD_LIMIT"],
                                        list_limit=TRELLO["LIST_LIMIT"])
            except TrelloNotFound:
                raise Error(
                    "Something happened to your Trello board! Was it deleted? Set-up cancelled."
                )
            except TrelloUnauthorized:
                raise Error(
                    "I've lost permissions to view your Trello board! Please run this command "
                    "again. Set-up cancelled.")

            for List in await trello_board.get_lists():
                if List.name == code:
                    return True

                for card in await List.get_cards():
                    if code in (card.name, card.desc):
                        return True

            return None, "Failed to find the code on your Trello board. Please try again."
Example #18
0
    async def change(self, CommandArgs):
        """change a server add-on"""

        response = CommandArgs.response
        prefix   = CommandArgs.prefix

        guild = CommandArgs.message.guild
        guild_data = CommandArgs.guild_data
        guild_addons = guild_data.get("addons", {})

        toggleable_addons = [str(x) for x in filter(lambda x: getattr(x, 'toggleable', True), addons.values())]

        parsed_args = await CommandArgs.prompt([
            {
                "prompt": f"Please choose the add-on you would like to change: ``{toggleable_addons}``",
                "name": "addon_choice",
                "type": "choice",
                "choices": toggleable_addons,
                "formatting": False
            },
            {
                "prompt": "Would you like to **enable** or **disable** this add-on?",
                "name": "enable",
                "type": "choice",
                "choices": ["enable", "disable"]
            },
        ], last=True)

        addon_choice = parsed_args["addon_choice"]
        enable = parsed_args["enable"] == "enable"

        if enable:
            if getattr(addons[addon_choice], "premium", False):
                donator_profile, _ = await get_features(Object(id=guild.owner_id), guild=guild)

                if not donator_profile.features.get("premium"):
                    raise Error(f"You must have premium in order to enable this add-on. Please use ``{prefix}donate`` "
                                "for instructions on donating.")

            await response.success(f"Successfully **{parsed_args['enable']}d** the **{addon_choice.title()}** add-on! You should "
                                   f"now see additional commands if you run ``{prefix}help``.")
        else:
            await response.success(f"Successfully **{parsed_args['enable']}d** the **{addon_choice.title()}** add-on! These "
                                   f"commands have been removed from your ``{prefix}help`` menu.")

        guild_addons[addon_choice] = enable
        guild_data["addons"] = guild_addons

        await self.r.table("guilds").insert(guild_data, conflict="update").run()

        await set_guild_value(guild, "addons", guild_addons)
Example #19
0
    async def add(self, CommandArgs):
        """add a new Magic Role to Bloxlink"""

        guild_data = CommandArgs.guild_data
        guild      = CommandArgs.guild
        response   = CommandArgs.response
        author     = CommandArgs.author
        prefix     = CommandArgs.prefix

        premium_status, _ = await get_features(discord.Object(id=guild.owner_id), guild=guild)

        if not premium_status.features.get("premium"):
            magic_roles_desc = "\n".join([f'**{x}** {ARROW} {y}' for x,y in MAGIC_ROLES.items()])
            raise Error("Customizing Magic Roles is reserved for __Bloxlink Premium subscribers!__ You may find out "
                        f"more information with the `{prefix}donate` command.\n\n"
                        "However, you may manually create a Bloxlink Magic Role "
                        f"and assign it one of these names, then give it to people!\n{magic_roles_desc}")

        parsed_args = await CommandArgs.prompt([
            {
                "prompt": "Which `role` would you like to use for this Magic Role?",
                "name": "role",
                "type": "role"
            },
            {
                "prompt": "Now the fun part! Let's choose what this Magic Role can do :sparkles:.\n\n"
                          "Please select the features this Magic Role can do.",
                "name": "features",
                "components": [discord.ui.Select(max_values=len(MAGIC_ROLES), options=[
                                discord.SelectOption(label=k, description=v)
                                for k,v in MAGIC_ROLES.items()
                ])],
                "type": "choice",
                "choices": ("Bloxlink Bypass", "Bloxlink Updater", "Bloxlink Admin")
            }
        ])

        role = parsed_args["role"]
        features = parsed_args["features"]

        magic_roles = guild_data.get("magicRoles", {})

        magic_roles[str(role.id)] = features
        guild_data["magicRoles"] = magic_roles

        await self.r.table("guilds").insert(guild_data, conflict="update").run()
        await set_guild_value(guild, "magicRoles", magic_roles)
        await post_event(guild, guild_data, "configuration", f"{author.mention} ({author.id}) has **added** a new `magicRole`!", BROWN_COLOR)

        await response.success("Successfully **saved** your new Magic Role! Go assign it to some people! :sparkles:")
Example #20
0
    async def __main__(self, ExtensionArgs):
        user = ExtensionArgs.resolved
        guild = ExtensionArgs.guild

        guild_data = ExtensionArgs.guild_data
        response = ExtensionArgs.response

        if user.bot:
            raise Error("You cannot update bots!", hidden=True)

        if isinstance(user, discord.User):
            try:
                user = await guild.fetch_member(user.id)
            except discord.errors.NotFound:
                raise Error("This user isn't in your server!")

        try:
            added, removed, nickname, errors, warnings, roblox_user = await guild_obligations(
                user,
                guild=guild,
                guild_data=guild_data,
                roles=True,
                nickname=True,
                cache=False,
                dm=False,
                event=True,
                exceptions=("BloxlinkBypass", "Blacklisted", "CancelCommand",
                            "UserNotVerified", "PermissionError", "RobloxDown",
                            "RobloxAPIError"))

            await response.send(
                f"{REACTIONS['DONE']} **Updated** {user.mention}", hidden=True)

        except BloxlinkBypass:
            raise Message(
                "Since this user has the Bloxlink Bypass role, I was unable to update their roles/nickname.",
                type="info",
                hidden=True)

        except Blacklisted as b:
            if isinstance(b.message, str):
                raise Error(
                    f"{user.mention} has an active restriction for: `{b}`",
                    hidden=True)
            else:
                raise Error(
                    f"{user.mention} has an active restriction from Bloxlink.",
                    hidden=True)

        except CancelCommand:
            pass

        except UserNotVerified:
            raise Error("This user is not linked to Bloxlink.", hidden=True)

        except PermissionError as e:
            raise Error(e.message, hidden=True)
Example #21
0
    async def __main__(self, CommandArgs):
        guild = CommandArgs.message.guild
        target = CommandArgs.parsed_args["target"]
        flags = CommandArgs.flags
        response = CommandArgs.response

        username = ID = False

        if "username" in flags:
            username = True
        elif target.isdigit():
            ID = True
        else:
            username = True

        #async with response.loading():
        try:
            account, _ = await get_user(username=username and target,
                                        roblox_id=ID and target)
        except RobloxNotFound:
            raise Error("This Roblox account doesn't exist.")
        else:
            roblox_id = account.id

            discord_ids = (await self.r.db("bloxlink").table(
                "robloxAccounts").get(roblox_id).run() or {}).get("discordIDs")

            results = []

            if discord_ids:
                for discord_id in discord_ids:
                    try:
                        user = await guild.fetch_member(int(discord_id))
                    except NotFound:
                        pass
                    else:
                        results.append(f"{user.mention} ({user.id})")

            embed = Embed(title=f"Reverse Search for {account.username}")
            embed.set_thumbnail(url=account.avatar)

            if results:
                embed.description = "\n".join(results)
            else:
                embed.description = "No results found."

            await response.send(embed=embed)
Example #22
0
    async def remove(self, CommandArgs):
        """allow a user or group back in your server"""

        guild = CommandArgs.guild
        response = CommandArgs.response

        guild_data = CommandArgs.guild_data
        restrictions = guild_data.get("restrictions", {})

        resolvable = (await CommandArgs.prompt([{
            "prompt":
            "Please either mention a user, give a Group URL, or a Roblox username.",
            "name":
            "resolvable",
            "validation":
            self.resolve_restriction
        }]))["resolvable"]

        if restrictions.get(resolvable[0], {}).get(str(resolvable[3])):
            restrictions[resolvable[0]].pop(str(resolvable[3]))

            if not restrictions[resolvable[0]]:
                restrictions.pop(resolvable[0], None)

            guild_data["restrictions"] = restrictions
            await set_guild_value(guild, "restrictions", restrictions)

            await self.r.table("guilds").insert(guild_data,
                                                conflict="replace").run()

            await response.success(
                f"Successfully **removed** this **{resolvable[1]}** from your restrictions."
            )

        else:
            raise Error(f"This **{resolvable[1]}** isn't restricted!")
Example #23
0
    async def __main__(self, CommandArgs):
        guild = CommandArgs.guild
        response = CommandArgs.response
        guild_data = CommandArgs.guild_data
        trello_board = CommandArgs.trello_board
        prefix = CommandArgs.prefix
        author = CommandArgs.author
        locale = CommandArgs.locale

        role_binds_trello, group_ids_trello, trello_binds_list = await get_binds(guild=guild, trello_board=trello_board)

        bind_count = count_binds(guild_data, role_binds=role_binds_trello, group_ids=group_ids_trello)

        if bind_count >= FREE_BIND_COUNT:
            profile, _ = await get_features(Object(id=guild.owner_id), guild=guild)

            if not profile.features.get("premium"):
                raise Error(locale("commands.bind.errors.noPremiumBindLimitExceeded", prefix=prefix, free_bind_count=FREE_BIND_COUNT, prem_bind_count=PREM_BIND_COUNT))

            if bind_count >= PREM_BIND_COUNT:
                raise Error(locale("commands.bind.errors.premiumBindLimitExceeded", prefix=prefix, prem_bind_count=PREM_BIND_COUNT))

        parsed_args = await CommandArgs.prompt([
            {
                "prompt": f"{locale('commands.bind.prompts.bindTypePrompt.line_1', arrow=ARROW)}\n"
                          f"{locale('commands.bind.prompts.bindTypePrompt.line_2', arrow=ARROW)}\n"
                          f"{locale('commands.bind.prompts.bindTypePrompt.line_3', arrow=ARROW)}\n"
                          f"{locale('commands.bind.prompts.bindTypePrompt.line_4', arrow=ARROW)}\n"
                          f"{locale('commands.bind.prompts.bindTypePrompt.line_5', arrow=ARROW)}",
                "name": "bind_choice",
                "type": "choice",
                "choices": locale("commands.bind.prompts.bindTypePrompt.choices"),
                "formatting": False
            },
            {
                "prompt": locale("commands.bind.prompts.nicknamePrompt.line", prefix=prefix, nickname_templates=NICKNAME_TEMPLATES),
                "name": "nickname",
                "max": 100,
                "type": "string",
                "footer": locale("commands.bind.prompts.nicknamePrompt.footer"),
                "formatting": False
            }
        ])

        bind_choice = parsed_args["bind_choice"].lower()
        nickname = parsed_args["nickname"]

        if trello_board:
            trello_binds_list = await trello_board.get_list(lambda l: l.name.lower() == "bloxlink binds")

            if not trello_binds_list:
                try:
                    trello_binds_list = await trello_board.create_list(name="Bloxlink Binds")
                except TrelloUnauthorized:
                        await response.error(locale("commands.bind.errors.trelloError"))
                except (TrelloNotFound, TrelloBadRequest):
                    pass

            trello_card_binds, _ = await parse_trello_binds(trello_board=trello_board, trello_binds_list=trello_binds_list)
        else:
            trello_binds_list = None
            trello_group_bind = None
            trello_card_binds = {
                "groups": {
                    "entire group": {},
                    "binds": {}
                },
                "assets": {},
                "badges": {},
                "gamePasses": {}
            }

        if nickname.lower() in (locale("prompt.skip"), locale("prompt.done"), locale("prompt.next")):
            nickname = None
            nickname_lower = None
        else:
            nickname_lower = nickname.lower()

        if bind_choice == locale("commands.bind.group"):
            parsed_args_group = await CommandArgs.prompt([
                {
                    "prompt": locale("commands.bind.prompts.groupPrompt.line"),
                    "name": "group",
                    "validation": self.validate_group
                },
                {
                "prompt": f"{locale('commands.bind.prompts.groupBindMode.line_1', arrow=ARROW)}\n"
                          f"{locale('commands.bind.prompts.groupBindMode.line_2', arrow=ARROW)}\n"
                          f"{locale('commands.bind.prompts.groupBindMode.line_3', arrow=ARROW)}",
                    "name": "type",
                    "type": "choice",
                    "choices": locale("commands.bind.prompts.groupBindMode.choices")
                }
            ])

            group = parsed_args_group["group"]
            group_id = group.group_id

            group_ids = guild_data.get("groupIDs", {})
            found_group = trello_card_binds["groups"]["entire group"].get(group_id) or group_ids.get(group_id)

            trello_group_bind = trello_card_binds["groups"]["entire group"].get(group_id)

            if parsed_args_group["type"] == locale("commands.bind.entireGroup"):
                if found_group:
                    if nickname and found_group["nickname"] != nickname:
                        group_ids[group_id] = {"nickname": nickname, "groupName": group.name}
                        guild_data["groupIDs"] = group_ids

                        await self.r.table("guilds").insert(guild_data, conflict="update").run()

                        trello_group_bind = trello_card_binds["groups"]["entire group"].get(group_id)

                        make_trello_card = True

                        if trello_group_bind and trello_group_bind["nickname"]:
                            for card_data in trello_group_bind["trello"].get("cards", []):
                                card = card_data["card"]

                                try:
                                    await card.edit(desc=card.description.replace(trello_group_bind["nickname"], nickname))
                                except TrelloUnauthorized:
                                    await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                         "Trello board.")
                                except (TrelloNotFound, TrelloBadRequest):
                                    pass

                                make_trello_card = False

                            if make_trello_card:
                                try:
                                    await trello_binds_list.create_card(name="Bloxlink Group Bind", desc=f"Group: {group_id}\nNickname: {nickname}")
                                except TrelloUnauthorized:
                                    await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                         "Trello board.")
                                except (TrelloNotFound, TrelloBadRequest):
                                    pass

                            if trello_binds_list:
                                trello_binds_list.parsed_bind_data = None

                        ending_s = group.name.endswith("s") and "'" or "'s"

                        await post_event(guild, guild_data, "bind", f"{author.mention} ({author.id}) has **changed** `{group.name}`{ending_s} nickname template.", BLURPLE_COLOR)

                        await clear_guild_data(guild)

                        raise Message("Since your group is already linked, the nickname was updated.", type="success")

                    else:
                        raise Message("This group is already linked.", type="silly")

                for roleset in group.rolesets:
                    roleset_name = roleset.get("name")
                    roleset_rank = roleset.get("rank")

                    if roleset_rank:
                        discord_role = find(lambda r: r.name == roleset_name, guild.roles)

                        if not discord_role:
                            try:
                                discord_role = await guild.create_role(name=roleset_name)
                            except Forbidden:
                                raise PermissionError("I was unable to create the Discord role. Please ensure my role has the `Manage Roles` permission.")

                # add group to guild_data.groupIDs
                group_ids[group_id] = {"nickname": nickname not in ("skip", "next") and nickname, "groupName": group.name}
                guild_data["groupIDs"] = group_ids

                await self.r.table("guilds").insert(guild_data, conflict="update").run()

                if trello_binds_list:
                    try:
                        await trello_binds_list.create_card(name="Bloxlink Group Bind", desc=f"Group: {group_id}\nNickname: {nickname}")
                    except TrelloUnauthorized:
                        await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                             "Trello board.")
                    except (TrelloNotFound, TrelloBadRequest):
                        pass

                await post_event(guild, guild_data, "bind", f"{author.mention} ({author.id}) has **linked** group `{group.name}`.", BLURPLE_COLOR)
                await clear_guild_data(guild)

                raise Message("Success! Your group was successfully linked.", type="success")

            else:
                # select ranks from their group
                # ask if they want to auto-create the binds or select a specific role
                # shows confirmation embed with arrows from rank to discord role

                discord_role = await CommandArgs.prompt([
                    {
                        "prompt": "Please provide **Discord role name(s)** for this bind, separated by commas.",
                        "name": "role",
                        "type": "role",
                        "multiple": True,
                        "max": 10
                    }
                ])

                discord_roles = discord_role["role"]

                new_ranks = {"binds":[], "ranges": []}

                role_binds = guild_data.get("roleBinds") or {}

                if isinstance(role_binds, list):
                    role_binds = role_binds[0]

                role_binds["groups"] = role_binds.get("groups") or {} # {"groups": {"ranges": {}, "binds": {}}}
                role_binds["groups"][group_id] = role_binds["groups"].get(group_id) or {}
                role_binds["groups"][group_id]["binds"] = role_binds["groups"][group_id].get("binds") or {}
                role_binds["groups"][group_id]["ranges"] = role_binds["groups"][group_id].get("ranges") or {}
                role_binds["groups"][group_id]["groupName"] = group.name

                rolesets_embed = Embed(title=f"{group.name} Rolesets", description="\n".join(f"**{x.get('name')}** {ARROW} {x.get('rank')}" for x in group.rolesets if x.get('rank')))

                rolesets_embed = await CommandArgs.response.send(embed=rolesets_embed)

                response.delete(rolesets_embed)

                failures = 0

                while True:
                    if failures == 5:
                        raise Error("Too many failed attempts. Please run this command again.")

                    selected_ranks = await CommandArgs.prompt([
                        {
                            "prompt": f"Please select the rolesets that should receive the role(s) **{', '.join([r.name for r in discord_roles])}**. "
                                       "You may specify the roleset name or ID. You may provide them in a list, "
                                       "or as a range. You may also say `everyone` to capture everyone in the group; "
                                       "and you can negate the number to catch everyone with the rank _and above._\n"
                                       "You can also say `guest` to include **all non-group members**.\n"
                                       "Example 1: `1,4,-6,VIP, 10, 50-100, Staff Members, 255`.\nExample 2: `"
                                       "-100` means everyone with rank 100 _and above._\nExample 3: `everyone` "
                                       "means everyone in the group.\n\n"
                                       "For your convenience, your Rolesets' names and IDs were sent above.",
                            "name": "ranks",
                            "formatting": False

                        }
                    ], last=True)

                    pending_roleset_names = []

                    for rank in selected_ranks["ranks"].split(","):
                        rank = rank.strip()

                        if rank.isdigit():
                            new_ranks["binds"].append(str(rank))
                        elif rank in ("all", "everyone"):
                            new_ranks["binds"].append("all")
                        elif rank in ("0", "guest"):
                            new_ranks["binds"].append("0")
                        elif rank[:1] == "-":
                            try:
                                int(rank)
                            except ValueError:
                                pass
                            else:
                                new_ranks["binds"].append(rank)
                        else:
                            range_search = bind_num_range.search(rank)

                            if range_search:
                                num1, num2 = range_search.group(1), range_search.group(2)
                                new_ranks["ranges"].append([num1, num2])
                            else:
                                # they specified a roleset name as a string
                                pending_roleset_names.append(rank)

                    if pending_roleset_names:
                        found = False

                        for roleset in group.rolesets:
                            roleset_name = roleset.get("name")
                            roleset_rank = roleset.get("rank")

                            if roleset_name in pending_roleset_names and roleset_name not in new_ranks["binds"]:
                                new_ranks["binds"].append(str(roleset_rank))
                                found = True

                        if not found:
                            response.delete(await response.error("Could not find a matching Roleset name. Please try again."))
                            failures += 1

                            continue

                    break

                if new_ranks["binds"]:
                    for x in new_ranks["binds"]:
                        rank = role_binds["groups"][group_id].get("binds", {}).get(x, {})

                        if not isinstance(rank, dict):
                            rank = {"nickname": nickname_lower, "roles": [str(rank)]}

                            for discord_role in discord_roles:
                                role_id = str(discord_role.id)

                                if role_id not in rank["roles"]:
                                    rank["roles"].append(role_id)
                        else:
                            for discord_role in discord_roles:
                                role_id = str(discord_role.id)

                                if role_id not in rank.get("roles", []):
                                    rank["roles"] = rank.get("roles") or []
                                    rank["roles"].append(role_id)

                                    if nickname_lower:
                                        rank["nickname"] = nickname
                                    else:
                                        if not rank.get("nickname"):
                                            rank["nickname"] = None

                        role_binds["groups"][group_id]["binds"][x] = rank
                        # trello binds:
                            # rank is in list of ranks
                                # update nickname
                                # append role
                            # else: make new card

                        if trello_binds_list:
                            make_binds_card = True

                            if trello_card_binds:
                                trello_bind_group = trello_card_binds["groups"]["binds"].get(group_id, {}).get("binds")

                                if trello_bind_group:
                                    card_data_ = trello_bind_group.get(x)

                                    if card_data_:
                                        for card in card_data_.get("trello", {}).get("cards", []):
                                            trello_card = card["card"]
                                            trello_ranks = card.get("ranks") or []

                                            if (x in trello_ranks or x == "all") and len(trello_ranks) == 1:
                                                trello_bind_roles = card.get("roles", set())
                                                card_bind_data = [
                                                    f"Group: {group_id}",
                                                    f"Nickname: {(nickname != 'skip' and nickname) or rank.get('nickname') or card_data_.get('nickname') or 'None'}",
                                                ]

                                                for discord_role in discord_roles:
                                                    trello_bind_roles.add(discord_role.name)

                                                card_bind_data.append(f"Roles: {', '.join(trello_bind_roles)}")
                                                card_bind_data.append(f"Ranks: {card['trello_str']['ranks']}")

                                                trello_card_desc = "\n".join(card_bind_data)

                                                if trello_card_desc != trello_card.description:
                                                    trello_card.description = trello_card_desc

                                                    try:
                                                        await trello_card.edit(desc=trello_card_desc)
                                                    except TrelloUnauthorized:
                                                        await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                                             "Trello board.")
                                                    except (TrelloNotFound, TrelloBadRequest):
                                                        pass

                                                    trello_binds_list.parsed_bind_data = None
                                                    make_binds_card = False

                                                    break

                            if make_binds_card:
                                card_bind_data = [
                                    f"Group: {group_id}",
                                    f"Nickname: {nickname != 'skip' and nickname or 'None'}",
                                    f"Roles: {', '.join([r.name for r in discord_roles])}",
                                ]

                                if x != "all":
                                    card_bind_data.append(f"Ranks: {x}")

                                trello_card_desc = "\n".join(card_bind_data)

                                try:
                                    card = await trello_binds_list.create_card(name="Bloxlink Bind", desc=trello_card_desc)
                                except TrelloUnauthorized:
                                    await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                         "Trello board.")
                                except (TrelloNotFound, TrelloBadRequest):
                                    pass

                                trello_binds_list.parsed_bind_data = None

                if new_ranks["ranges"]:
                    role_binds["groups"][group_id]["ranges"] = role_binds["groups"][group_id].get("ranges") or []

                    for x in new_ranks["ranges"]: # list of dictionaries: [{"high": 10, "low": 1, "nickname": ""},...]
                        range_, num = self.find_range(x, role_binds["groups"][group_id]["ranges"])
                        found = bool(range_)

                        for discord_role in discord_roles:
                            role_id = str(discord_role.id)

                            if not role_id in range_.get("roles", []):
                                range_["roles"] = range_.get("roles") or []
                                range_["roles"].append(role_id)

                                if nickname_lower:
                                    range_["nickname"] = nickname
                                else:
                                    if not range_.get("nickname"):
                                        range_["nickname"] = None

                        if found:
                            role_binds["groups"][group_id]["ranges"][num] = range_
                        else:
                            range_["low"] = int(x[0])
                            range_["high"] = int(x[1])
                            role_binds["groups"][group_id]["ranges"].append(range_)

                        if trello_binds_list:
                            make_binds_card = True

                            if trello_card_binds:
                                trello_range_group = trello_card_binds["groups"]["binds"].get(group_id, {}).get("ranges")

                                if trello_range_group:
                                    for trello_range in trello_range_group:
                                        trello_data = trello_range["trello"]

                                        for card in trello_data.get("cards", []):
                                            trello_card = card["card"]
                                            trello_ranks = card.get("ranks", [])

                                            if trello_range["low"] == range_["low"] and trello_range["high"] == range_["high"] and len(trello_ranks) == 1:
                                                trello_data = trello_range["trello"]
                                                trello_bind_roles = trello_range.get("roles", set())
                                                card_bind_data = [
                                                    f"Group: {group_id}",
                                                    f"Nickname: {(nickname != 'skip' and nickname) or trello_range.get('nickname') or 'None'}",
                                                ]

                                                for discord_role in discord_roles:
                                                    trello_bind_roles.add(discord_role.name)

                                                card_bind_data.append(f"Roles: {', '.join(trello_bind_roles)}")
                                                card_bind_data.append(f"Ranks: {card['trello_str']['ranks']}")

                                                trello_card_desc = "\n".join(card_bind_data)

                                                if trello_card_desc != trello_card.description:
                                                    trello_card.description = trello_card_desc

                                                    try:
                                                        await trello_card.edit(desc=trello_card_desc)
                                                    except TrelloUnauthorized:
                                                        await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                                             "Trello board.")
                                                    except (TrelloNotFound, TrelloBadRequest):
                                                        pass

                                                    trello_binds_list.parsed_bind_data = None
                                                    make_binds_card = False

                                                    break

                            if make_binds_card:
                                card_bind_data = [
                                    f"Group: {group_id}",
                                    f"Nickname: {nickname != 'skip' and nickname or 'None'}",
                                    f"Roles: {', '.join([r.name for r in discord_roles])}",
                                    f"Ranks: {range_['low']}-{range_['high']}"
                                ]

                                trello_card_desc = "\n".join(card_bind_data)

                                try:
                                    card = await trello_binds_list.create_card(name="Bloxlink Range Bind", desc=trello_card_desc)
                                except TrelloUnauthorized:
                                    await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                         "Trello board.")
                                except (TrelloNotFound, TrelloBadRequest):
                                    pass

                                trello_binds_list.parsed_bind_data = None


            await self.r.table("guilds").insert({
                "id": str(guild.id),
                "roleBinds": role_binds
            }, conflict="update").run()

            text = ["Successfully **bound** rank ID(s): `"]
            if new_ranks["binds"]:
                text.append(", ".join(new_ranks["binds"]))

            if new_ranks["ranges"]:
                text2 = ""

                if new_ranks["binds"]:
                    text2 = "; "

                text.append(f"{text2}ranges: {', '.join([r[0] + ' - ' + r[1] for r in new_ranks['ranges']])}")

            text.append(f"` with Discord role(s) **{', '.join([r.name for r in discord_roles])}**.")

            text = "".join(text)

            await post_event(guild, guild_data, "bind", f"{author.mention} ({author.id}) has **bound** group `{group.name}`.", BLURPLE_COLOR)

            await clear_guild_data(guild)

            await response.success(text)

        elif bind_choice in ("asset", "badge", "gamepass"):
            if bind_choice == "gamepass":
                bind_choice_title = "GamePass"
                bind_choice_plural = "gamePasses"
            else:
                bind_choice_title = bind_choice.title()
                bind_choice_plural = f"{bind_choice}s"

            vg_parsed_args = await CommandArgs.prompt([
                {
                   "prompt": f"Please provide the **{bind_choice_title} ID** to use for this bind.",
                   "name": "bind_id",
                   "type": "number",
                   "formatting": False
                },
                {
                   "prompt": "Please provide **Discord role name(s)** for this bind, separated by commas.",
                   "name": "role",
                   "type": "role",
                   "multiple": True,
                   "max": 10
                },
            ], last=True)

            discord_roles = vg_parsed_args["role"]
            bind_id = str(vg_parsed_args["bind_id"])

            if bind_choice == "asset":
                try:
                    text, response_ = await fetch(f"{API_URL}/marketplace/productinfo?assetId={bind_id}")
                except RobloxNotFound:
                    raise Error(f"An Asset with ID `{bind_id}` does not exist.")

                json_data = await response_.json()

                display_name = json_data.get("Name")

            elif bind_choice == "badge":
                try:
                    text, response_ = await fetch(f"https://badges.roblox.com/v1/badges/{bind_id}")
                except RobloxNotFound:
                    raise Error(f"A Badge with ID `{bind_id}` does not exist.")

                json_data = await response_.json()

                display_name = json_data.get("displayName")

            elif bind_choice == "gamepass":
                bind_choice_title = "GamePass"
                bind_choice_plural = "gamePasses"

                try:
                    text, response_ = await fetch(f"http://api.roblox.com/marketplace/game-pass-product-info?gamePassId={bind_id}")
                except (RobloxNotFound, RobloxAPIError):
                    raise Error(f"A GamePass with ID `{bind_id}` does not exist.")

                json_data = await response_.json()

                if json_data.get("ProductType") != "Game Pass":
                    raise Error(f"A GamePass with ID `{bind_id}` does not exist.")

                display_name = json_data.get("Name")


            role_binds = guild_data.get("roleBinds") or {}

            if isinstance(role_binds, list):
                role_binds = role_binds[0]

            role_binds[bind_choice_plural] = role_binds.get(bind_choice_plural) or {}
            role_binds[bind_choice_plural][bind_id] = role_binds[bind_choice_plural].get(bind_id) or {}

            role_binds[bind_choice_plural][bind_id]["nickname"] = nickname
            role_binds[bind_choice_plural][bind_id]["displayName"] = display_name

            role_binds[bind_choice_plural][bind_id]["roles"] = role_binds[bind_choice_plural][bind_id].get("roles", [])

            roles = role_binds[bind_choice_plural][bind_id]["roles"]

            for discord_role in discord_roles:
                role_id = str(discord_role.id)

                if not role_id in roles:
                    roles.append(role_id)

            role_binds[bind_choice_plural][bind_id]["roles"] = roles

            if trello_binds_list:
                make_binds_card = True

                if trello_card_binds:
                    trello_bind_vg = trello_card_binds.get(bind_choice_plural, {}).get(bind_id)

                    if trello_bind_vg:
                        trello_bind_roles = set(trello_bind_vg.get("roles", set()))

                        for card in trello_bind_vg.get("trello", {})["cards"]:
                            trello_card = card["card"]

                            card_bind_data = [
                                f"{bind_choice_title} ID: {bind_id}",
                                f"Display Name: {display_name}",
                                f"Nickname: {(nickname != 'skip' and nickname) or trello_bind_vg.get('nickname') or 'None'}",
                            ]

                            for discord_role in discord_roles:
                                trello_bind_roles.add(discord_role.name)

                            card_bind_data.append(f"Roles: {', '.join(trello_bind_roles)}")

                            trello_card_desc = "\n".join(card_bind_data)

                            if trello_card_desc != trello_card.description:
                                trello_card.description = trello_card_desc

                                try:
                                    await trello_card.edit(desc=trello_card_desc)
                                except TrelloUnauthorized:
                                    await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                                         "Trello board.")
                                except (TrelloNotFound, TrelloBadRequest):
                                    pass

                                trello_binds_list.parsed_bind_data = None
                                make_binds_card = False

                                break

                if make_binds_card:
                    card_bind_data = [
                        f"{bind_choice_title} ID: {bind_id}",
                        f"Display Name: {display_name}",
                        f"Nickname: {nickname != 'skip' and nickname or 'None'}",
                        f"Roles: {', '.join([d.name for d in discord_roles])}",
                    ]

                    trello_card_desc = "\n".join(card_bind_data)

                    try:
                        card = await trello_binds_list.create_card(name=f"Bloxlink {bind_choice_title} Bind", desc=trello_card_desc)
                    except TrelloUnauthorized:
                        await response.error("In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                             "Trello board.")
                    except (TrelloNotFound, TrelloBadRequest):
                        pass

                    trello_binds_list.parsed_bind_data = None

            await self.r.table("guilds").insert({
                "id": str(guild.id),
                "roleBinds": role_binds
            }, conflict="update").run()


            await post_event(guild, guild_data, "bind", f"{author.mention} ({author.id}) has **bound** {bind_choice_title} `{display_name}`.", BLURPLE_COLOR)

            await clear_guild_data(guild)

            await response.success(f"Successfully **bound** {bind_choice_title} `{display_name}` ({bind_id}) with Discord role(s) **{', '.join([r.name for r in discord_roles])}!**")
Example #24
0
    async def restore(self, CommandArgs):
        """restore your Server Data"""

        message = CommandArgs.message
        author = CommandArgs.message.author
        guild = CommandArgs.message.guild
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        if author.id == OWNER:
            if message.attachments:
                attachment = message.attachments[0]

                if not attachment.height:
                    file_data = await attachment.read()
                    json_data = file_data.decode("utf8").replace("'", '"')
                    json_data = json.loads(json_data)
                    json_data["id"] = str(guild.id)

                    if json_data.get("roleBinds"):
                        role_map = {}

                        for bind_type, bind_data in json_data.get("roleBinds", {}).items():
                            if bind_type == "groups":
                                for group_id, group_data in bind_data.items():
                                    for rank, rank_data in group_data.get("binds", {}).items():
                                        for role_id in rank_data.get("roles", []):
                                            if not guild.get_role(int(role_id)):
                                                role_map_find = role_map.get(role_id)

                                                if not role_map_find:
                                                    role = await guild.create_role(name=rank*6)
                                                    role_map[role_id] = str(role.id)
                                                    role_map_find = str(role.id)

                                                json_data["roleBinds"]["groups"][group_id]["binds"][rank]["roles"].remove(role_id)
                                                json_data["roleBinds"]["groups"][group_id]["binds"][rank]["roles"].append(role_map_find)

                    await self.r.table("guilds").insert(json_data, conflict="replace").run()

                    return await response.success("Successfully **restored** this server's data.")
                else:
                    raise Error("You must supply a non-image file for data restore.")


        user_data = await self.r.db("bloxlink").table("users").get(str(author.id)).run() or {}
        user_backups = user_data.get("backups", [])

        if not user_backups:
            raise Message(f"You don't have any backups created! You may create them with ``{prefix}data backup``.", type="silly")

        embed = Embed(title="Bloxlink Data Restore", description="Please select the backup you could like to restore with the reactions.")

        for i, backup in enumerate(user_backups):
            guild_data = backup["data"]
            backup_name = backup["backupName"]
            timestamp = datetime.datetime.fromtimestamp(backup["timestamp"])

            trello_board = await get_board(guild_data=guild_data, guild=guild)
            prefix, _ = await get_prefix(guild=guild, trello_board=trello_board)

            backup["prefix"] = prefix
            backup["trello_board"] = trello_board,
            backup["timestamp"] = timestamp
            backup["nickname_template"] = guild_data.get("nicknameTemplate", DEFAULTS.get("nicknameTemplate"))

            if trello_board:
                trello_options, _ = await get_options(trello_board)
                guild_data.update(trello_options)

            len_role_binds = count_binds(guild_data)
            backup["len_role_binds"] = len_role_binds

            embed.add_field(name=f"{INT_REACTIONS[i]} {ARROW} {backup_name}", value="\n".join([
                f"**Role Binds** {ARROW} {len_role_binds}",
                f"**Prefix** {ARROW} {prefix}",
                f"**Nickname Template** {ARROW} {backup['nickname_template']}",
                f"**Created on ** {timestamp.strftime('%b. %d, %Y (%A)')}"
            ]))

        message = await response.send(embed=embed)

        if message:
            response.delete(message)

            for i, _ in enumerate(user_backups):
                emote_string = INT_REACTIONS[i]

                try:
                    await message.add_reaction(emote_string)
                except Forbidden:
                    raise PermissionError("I'm missing permission to add reactions to your message!")

            try:
                reaction, _ = await Bloxlink.wait_for("reaction_add", timeout=PROMPT["PROMPT_TIMEOUT"], check=self._reaction_check(author))
            except TimeoutError:
                raise CancelledPrompt(f"timeout ({PROMPT['PROMPT_TIMEOUT']}s)")
            else:
                chosen_backup = None
                str_reaction = str(reaction)

                for i, reaction_string in enumerate(INT_REACTIONS):
                    if str_reaction == reaction_string:
                        chosen_backup = user_backups[i]

                if chosen_backup:
                    parsed_args = await CommandArgs.prompt([
                        {
                            "prompt": "**Warning!** This will **__restore__ ALL OF YOUR SETTINGS** including:\n"
                                      f"**{chosen_backup['len_role_binds']}** Role Binds\n"
                                      f"**{chosen_backup['prefix']}** prefix\n"
                                      f"**{chosen_backup['nickname_template']}** Nickname Template\n"
                                      "Continue? ``Y/N``",
                            "name": "confirm",
                            "type": "choice",
                            "formatting": False,
                            "choices": ("yes", "no"),
                            "embed_title": "Warning!",
                            "embed_color": ORANGE_COLOR,
                            "footer": "Say **yes** to continue, or **no** to cancel."
                        }
                    ])

                    if parsed_args["confirm"] == "yes":
                        await self._restore(guild, chosen_backup)
                        await response.success("Successfully **restored** your backup!")
                    else:
                        raise CancelledPrompt("cancelled restore")
Example #25
0
    async def __main__(self, CommandArgs):
        response = CommandArgs.response

        user_slash = CommandArgs.parsed_args.get("user")
        role_slash = CommandArgs.parsed_args.get("role")
        users_ = CommandArgs.parsed_args.get("users") or (
            [user_slash, role_slash] if user_slash or role_slash else None)
        prefix = CommandArgs.prefix

        message = CommandArgs.message
        author = CommandArgs.author
        guild = CommandArgs.guild

        guild_data = CommandArgs.guild_data

        users = []

        if not (users_ and CommandArgs.has_permission):
            if not users_:
                if message:
                    message.content = f"{prefix}getrole"
                    return await parse_message(message)
                else:
                    raise Message(
                        f"To update yourself, please run the `{prefix}getrole` command.",
                        hidden=True,
                        type="info")
            else:
                raise Message(
                    "You do not have permission to update users; you need the `Manage Roles` permission, or "
                    "a role called `Bloxlink Updater`.",
                    type="info",
                    hidden=True)

        if isinstance(users_[0], Role):
            if not guild.chunked:
                await guild.chunk()

            for role in users_:
                users += role.members

            if not users:
                raise Error("These role(s) have no members in it!",
                            hidden=True)
        else:
            users = users_

        len_users = len(users)

        if self.redis:
            redis_cooldown_key = self.REDIS_COOLDOWN_KEY.format(
                release=RELEASE, id=guild.id)
            on_cooldown = await self.redis.get(redis_cooldown_key)

            if len_users > 3 and on_cooldown:
                cooldown_time = math.ceil(
                    await self.redis.ttl(redis_cooldown_key) / 60)

                if not cooldown_time or cooldown_time == -1:
                    await self.redis.delete(redis_cooldown_key)
                    on_cooldown = None

                if on_cooldown:
                    if on_cooldown == 1:
                        raise Message(f"This server is still queued.")
                    elif on_cooldown == 2:
                        raise Message(
                            "This server's scan is currently running.")
                    elif on_cooldown == 3:
                        cooldown_time = math.ceil(
                            await self.redis.ttl(redis_cooldown_key) / 60)

                        raise Message(
                            f"This server has an ongoing cooldown! You must wait **{cooldown_time}** more minutes."
                        )

            donator_profile, _ = await get_features(Object(id=guild.owner_id),
                                                    guild=guild)
            premium = donator_profile.features.get("premium")

            if not premium:
                donator_profile, _ = await get_features(author)
                premium = donator_profile.features.get("premium")

            cooldown = 0

            if len_users > 10:
                if not premium:
                    raise Error(
                        "You need premium in order to update more than 10 members at a time! "
                        f"Use `{prefix}donate` for instructions on donating.")

                if len_users >= 100:
                    cooldown = math.ceil(((len_users / 1000) * 120) * 60)
                else:
                    cooldown = 120

                if self.redis:
                    await self.redis.set(redis_cooldown_key, 2, ex=86400)

            trello_board = CommandArgs.trello_board

            #async with response.loading():
            if len_users > 1:
                for user in users:
                    if not user.bot:
                        try:
                            added, removed, nickname, errors, warnings, roblox_user = await guild_obligations(
                                user,
                                guild=guild,
                                guild_data=guild_data,
                                trello_board=trello_board,
                                roles=True,
                                nickname=True,
                                dm=False,
                                exceptions=("BloxlinkBypass",
                                            "UserNotVerified", "Blacklisted",
                                            "PermissionError", "RobloxDown"),
                                cache=False)
                        except BloxlinkBypass:
                            if len_users <= 10:
                                await response.info(
                                    f"{user.mention} **bypassed**")
                        except UserNotVerified:
                            if len_users <= 10:
                                await response.send(
                                    f"{REACTIONS['ERROR']} {user.mention} is **not linked to Bloxlink**"
                                )
                        except PermissionError as e:
                            raise Error(e.message)
                        except Blacklisted as b:
                            if len_users <= 10:
                                await response.send(
                                    f"{REACTIONS['ERROR']} {user.mention} has an active restriction."
                                )
                        else:
                            if len_users <= 10:
                                await response.send(
                                    f"{REACTIONS['DONE']} **Updated** {user.mention}"
                                )
            else:
                user = users[0]

                if user.bot:
                    raise Message("Bots can't have Roblox accounts!",
                                  type="silly")

                old_nickname = user.display_name

                try:
                    added, removed, nickname, errors, warnings, roblox_user = await guild_obligations(
                        user,
                        guild=guild,
                        guild_data=guild_data,
                        trello_board=trello_board,
                        roles=True,
                        nickname=True,
                        cache=False,
                        dm=False,
                        event=True,
                        exceptions=("BloxlinkBypass", "Blacklisted",
                                    "CancelCommand", "UserNotVerified",
                                    "PermissionError", "RobloxDown",
                                    "RobloxAPIError"))

                    _, embed = await format_update_embed(
                        roblox_user,
                        user,
                        added=added,
                        removed=removed,
                        errors=errors,
                        warnings=warnings,
                        nickname=nickname
                        if old_nickname != nickname else None,
                        prefix=prefix,
                        guild_data=guild_data)

                    await response.send(embed=embed)

                except BloxlinkBypass:
                    raise Message(
                        "Since this user has the Bloxlink Bypass role, I was unable to update their roles/nickname.",
                        type="info")

                except Blacklisted as b:
                    if isinstance(b.message, str):
                        raise Error(
                            f"{user.mention} has an active restriction for: `{b}`"
                        )
                    else:
                        raise Error(
                            f"{user.mention} has an active restriction from Bloxlink."
                        )

                except CancelCommand:
                    pass

                except UserNotVerified:
                    raise Error("This user is not linked to Bloxlink.")

                except PermissionError as e:
                    raise Error(e.message)

            if cooldown:
                await self.redis.set(redis_cooldown_key, 3, ex=cooldown)

            if len_users > 10:
                await response.success("All users updated.")
Example #26
0
    async def __main__(self, CommandArgs):
        guild = CommandArgs.message.guild
        author = CommandArgs.message.author
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        guild_data = CommandArgs.guild_data
        group_ids = guild_data.get("groupIDs", {})

        settings_buffer = []

        parsed_args_1 = {}
        parsed_args_2 = {}
        parsed_args_3 = {}
        parsed_args_4 = {}

        nickname = None

        parsed_args_1 = await CommandArgs.prompt([{
            "prompt":
            "**Thank you for choosing Bloxlink!** In a few simple prompts, **we'll configure Bloxlink for your server.**\n\n"
            "**Pre-configuration:**\nBefore continuing, please ensure that Bloxlink has all the proper permissions, "
            "such as the ability to ``manage roles, nicknames, channels``, etc. If you do not set these "
            "permissions, you may encounter issues with using certain commands.",
            "name":
            "_",
            "footer":
            "Say **next** to continue.",
            "type":
            "choice",
            "choices": ["next"],
            "embed_title":
            "Setup Prompt"
        }, {
            "prompt":
            "Would you like to link a **Roblox group** to this Discord server? Please provide the **Group URL, or Group ID**.",
            "name":
            "group",
            "footer":
            "Say **skip** to leave as-is.",
            "embed_title":
            "Setup Prompt",
            "validation":
            self.validate_group
        }, {
            "prompt":
            "Would you like to change the **Verified role** (the role people are given if they're linked to Bloxlink) name to something else?\n"
            "Default: ``Verified``",
            "name":
            "verified_role",
            "footer":
            "Say **disable** to disable the Verified role.\nSay **skip** to leave as-is.",
            "embed_title":
            "Setup Prompt",
            "max":
            50
        }, {
            "prompt":
            "Would you like to link a **Trello.com board** to this server? You'll be able to change Bloxlink settings and binds from "
            "the board. Please either provide the **Trello board ID, or the board URL.**",
            "name":
            "trello_board",
            "footer":
            "Say **disable** to disable/clear a saved board.\nSay **skip** to leave as-is.",
            "embed_title":
            "Setup Prompt",
            "validation":
            self.validate_trello_board
        }],
                                                 dm=True,
                                                 no_dm_post=False)

        for k, v in parsed_args_1.items():
            if k != "_":
                settings_buffer.append(f"**{k}** {ARROW} {v}")

        group = parsed_args_1["group"]
        verified = parsed_args_1["verified_role"]

        trello_board = parsed_args_1["trello_board"]

        if group not in ("next", "skip"):
            group_ids[group.group_id] = {
                "nickname": nickname,
                "groupName": group.name
            }

            parsed_args_2 = await CommandArgs.prompt([{
                "prompt":
                "Should these members be given a nickname? Please create a nickname using these templates. You may "
                f"combine templates. The templates MUST match exactly.\n\n**Templates:** ```{NICKNAME_TEMPLATES}```",
                "name":
                "nickname",
                "embed_title":
                "Setup Prompt",
                "footer":
                "Say **disable** to not have a nickname.\nSay **skip** to leave this as the default.",
                "formatting":
                False
            }, {
                "prompt":
                "Would you like to automatically transfer your Roblox group ranks to Discord roles?\nValid choices:\n"
                "``merge`` — This will **NOT** remove any roles. Your group Rolesets will be **merged** with your current roles.\n"
                "``replace`` — **This will REMOVE and REPLACE your CURRENT ROLES** with your Roblox group Rolesets. You'll "
                "need to configure permissions and colors yourself.\n"
                "``skip`` — nothing will be changed.\n\nValid choices: (merge/replace/skip)",
                "name":
                "merge_replace",
                "type":
                "choice",
                "choices": ["merge", "replace", "skip", "next"],
                "footer":
                "Say either **merge**, **replace**, or **skip**",
                "embed_title":
                "Setup Prompt"
            }],
                                                     dm=True,
                                                     no_dm_post=True)

            if parsed_args_2["merge_replace"] == "next":
                parsed_args_2["merge_replace"] = "skip"

            nickname = parsed_args_2["nickname"]
            nickname_lower = nickname.lower()

            if nickname_lower == "skip":
                if group.group_id in group_ids:
                    nickname = group_ids[group.group_id]["nickname"]
                else:
                    nickname = NICKNAME_DEFAULT

            elif nickname_lower == "disable":
                nickname = None

            group_ids[group.group_id] = {
                "nickname": nickname,
                "groupName": group.name
            }

        for k, v in parsed_args_2.items():
            if k != "_":
                settings_buffer.append(f"**{k}** {ARROW} {v}")

        if trello_board not in ("skip", "disable"):
            trello_code = generate_code()

            parsed_args_3 = await CommandArgs.prompt([{
                "prompt":
                "We'll now attempt to verify that you own this Trello board. To begin, please add ``[email protected]`` (@bloxlink) "
                "to your Trello board. Then, say ``next`` to continue.",
                "name":
                "trello_continue",
                "type":
                "choice",
                "choices": ["next"],
                "footer":
                "Say **next** to continue.",
                "embed_title":
                "Trello Verification"
            }, {
                "prompt":
                f"Now, please make a card _anywhere_ on your Trello board with this code as the card name or description:```{trello_code}```\n"
                "Please note that up to **100** cards will be loaded from your Trello board, and up to **10** lists will be "
                "loaded. So, if you have more cards or lists, you'll need to archive some or use a different Trello board.",
                "name":
                "trello_continue",
                "type":
                "choice",
                "choices": ["next", "done"],
                "footer":
                "Say **done** after the code is on your Trello board.",
                "embed_title":
                "Trello Verification",
                "validation":
                await self.verify_trello_board(trello_board, trello_code)
            }],
                                                     dm=True,
                                                     no_dm_post=True)

        parsed_args_4 = await CommandArgs.prompt([{
            "prompt":
            "You have reached the end of the setup. Here are your current settings:\n"
            + "\n".join(settings_buffer),
            "name":
            "setup_complete",
            "type":
            "choice",
            "footer":
            "Please say **done** to complete the setup.",
            "choices": ["done"],
            "embed_title":
            "Setup Prompt Confirmation",
            "embed_color":
            BROWN_COLOR,
            "formatting":
            False
        }],
                                                 dm=True,
                                                 no_dm_post=True)

        if group and group != "skip":
            merge_replace = parsed_args_2.get("merge_replace")

            if merge_replace not in ("skip", "next"):
                if merge_replace == "replace":
                    for role in list(guild.roles):
                        try:
                            if not (role in guild.me.roles
                                    or role.is_default()):
                                try:
                                    await role.delete(
                                        reason=
                                        f"{author} chose to replace roles through {prefix}setup"
                                    )
                                except Forbidden:
                                    pass
                                except HTTPException:
                                    pass
                        except AttributeError:  # guild.me is None -- bot kicked out
                            raise CancelCommand

                sorted_rolesets = sorted(group.rolesets,
                                         key=lambda r: r.get("rank"),
                                         reverse=True)

                for roleset in sorted_rolesets:
                    roleset_name = roleset.get("name")
                    # roleset_rank = roleset.get("rank")

                    if not find(lambda r: r.name == roleset_name, guild.roles):
                        try:
                            await guild.create_role(name=roleset_name)
                        except Forbidden:
                            raise Error(
                                "Please ensure I have the ``Manage Roles`` permission; setup aborted."
                            )

        if verified:
            if verified == "disable":
                guild_data["verifiedRoleEnabled"] = False
            elif verified not in ("next", "skip"):
                guild_data["verifiedRoleName"] = verified
                guild_data["verifiedRoleEnabled"] = True

        if trello_board:
            update_trello = False

            if trello_board == "disable":
                trello_board = None
                update_trello = True
            elif trello_board in ("skip", "next"):
                trello_board = guild_data.get("trelloID")
            else:
                trello_board = trello_board.id
                update_trello = True

            if update_trello:
                guild_data["trelloID"] = trello_board

        if group_ids:
            guild_data["groupIDs"] = group_ids

        await self.r.table("guilds").insert(guild_data,
                                            conflict="replace").run()

        await post_event(
            guild, guild_data, "configuration",
            f"{author.mention} ({author.id}) has **set-up** the server.",
            BROWN_COLOR)

        await clear_guild_data(guild)

        await response.success(
            "Your server is now **configured** with Bloxlink!",
            dm=True,
            no_dm_post=True)

        if trello_board and update_trello:
            trello_info_embed = Embed(title="Trello Information")
            trello_info_embed.description = "Now that you've linked your Trello board, you may now modify Bloxlink settings and Role Binds from " \
                                            "the board. **No cards will be created right away;** cards are created **as you use commands**. For " \
                                            f"example, if you use ``{prefix}settings`` or ``{prefix}bind``, then cards will be created/edited.\n\n" \
                                            "Any pre-existing settings or binds will be simply be **merged** with any Trello settings/binds **unless " \
                                            f"you switch \"``trelloBindMode``\" to ``replace`` through the ``{prefix}settings`` command.**"

            await response.send(embed=trello_info_embed,
                                dm=True,
                                no_dm_post=True)
Example #27
0
    async def __main__(self, CommandArgs):
        choice = CommandArgs.parsed_args["choice"]
        guild_data = CommandArgs.guild_data
        groups = CommandArgs.guild_data.get("groupLock", {})
        guild = CommandArgs.guild
        author = CommandArgs.author
        prefix = CommandArgs.prefix
        response = CommandArgs.response

        if choice == "add":
            args = await CommandArgs.prompt([{
                "prompt":
                "Please specify either the **Group ID** or **Group URL** that you would like "
                "to set as a requirement for new joiners.",
                "name":
                "group",
                "validation":
                self.validate_group
            }, {
                "prompt":
                "Should only a **specific Roleset** be allowed to join your server? You may specify a Roleset name or ID. You may "
                "provide them in a list, and you may negate the number to capture everyone catch everyone with the rank _and above_.\n"
                "Example: `-10, 5, VIP` means people who are ranked 5, VIP, or if their roleset is greater than 10 can join your server.",
                "name":
                "rolesets",
                "footer":
                "Say **skip** to skip this option; if skipped, the roleset people have wouldn't matter, they'll be able to enter "
                "your server as long as they're in your group.",
                "type":
                "list",
                "exceptions": ("skip", ),
                "max":
                10,
            }, {
                "prompt":
                "Would you like people who are kicked to receive a custom DM? Please specify either `yes` or `no`.\n\n"
                "Note that Unverified users will receive a different DM on instructions to linking to Bloxlink.",
                "name":
                "dm_enabled",
                "type":
                "choice",
                "choices": ["yes", "no"]
            }])

            group = args["group"]
            dm_enabled = args["dm_enabled"] == "yes"
            rolesets_raw = args[
                "rolesets"] if args["rolesets"] != "skip" else None

            parsed_rolesets = []

            if rolesets_raw:
                for roleset in rolesets_raw:
                    if roleset.isdigit():
                        parsed_rolesets.append(int(roleset))
                    elif roleset[:1] == "-":
                        try:
                            roleset = int(roleset)
                        except ValueError:
                            pass
                        else:
                            parsed_rolesets.append(roleset)
                    else:
                        range_search = self._range_search.search(roleset)

                        if range_search:
                            num1, num2 = range_search.group(
                                1), range_search.group(2)
                            parsed_rolesets.append([int(num1), int(num2)])
                        else:
                            # they specified a roleset name as a string

                            roleset_find = group.rolesets.get(roleset.lower())

                            if roleset_find:
                                parsed_rolesets.append(roleset_find[1])

                if not parsed_rolesets:
                    raise Error(
                        "Could not resolve any valid rolesets! Please make sure you're typing the Roleset name correctly."
                    )

            if len(groups) >= 15:
                raise Message(
                    "15 groups is the max you can add to your group-lock! Please delete some before adding any more.",
                    type="silly")

            profile, _ = await get_features(Object(id=guild.owner_id),
                                            guild=guild)

            if len(groups) >= 3 and not profile.features.get("premium"):
                raise Message(
                    "If you would like to add more than **3** groups to your group-lock, then you need Bloxlink Premium.\n"
                    f"Please use `{prefix}donate` for instructions on receiving Bloxlink Premium.\n"
                    "Bloxlink Premium members may lock their server with up to **15** groups.",
                    type="info")

            if dm_enabled:
                dm_message = (await CommandArgs.prompt([{
                    "prompt":
                    "Please specify the text of the DM that people who are kicked will receive. A recommendation "
                    "is to provide your Group Link and any other instructions for them.",
                    "name":
                    "dm_message",
                    "max":
                    1500
                }],
                                                       last=True)
                              )["dm_message"]
            else:
                dm_message = None

            groups[group.group_id] = {
                "groupName": group.name,
                "dmMessage": dm_message,
                "roleSets": parsed_rolesets
            }

            await self.r.table("guilds").insert(
                {
                    "id": str(guild.id),
                    "groupLock": groups
                }, conflict="update").run()

            await post_event(
                guild, guild_data, "configuration",
                f"{author.mention} ({author.id}) has **added** a group to the `server-lock`.",
                BROWN_COLOR)

            await set_guild_value(guild, "groupLock", groups)

            await response.success(
                f"Successfully added group **{group.name}** to your Server-Lock!"
            )

        elif choice == "delete":
            group = (await CommandArgs.prompt([{
                "prompt":
                "Please specify either the **Group URL** or **Group ID** to delete.",
                "name":
                "group",
                "validation":
                self.validate_group
            }],
                                              last=True))["group"]

            if not groups.get(group.group_id):
                raise Message("This group isn't in your server-lock!")

            del groups[group.group_id]
            guild_data["groupLock"] = groups

            if groups:
                await self.r.table("guilds").insert(guild_data,
                                                    conflict="replace").run()
            else:
                guild_data.pop("groupLock")

                await self.r.table("guilds").insert(guild_data,
                                                    conflict="replace").run()

            await post_event(
                guild, guild_data, "configuration",
                f"{author.mention} ({author.id}) has **deleted** a group from the `server-lock`.",
                BROWN_COLOR)

            await set_guild_value(guild, "groupLock", groups)

            await response.success(
                "Successfully **deleted** your group from the Server-Lock!")

        elif choice == "view":
            if not groups:
                raise Message("You have no groups added to your Server-Lock!",
                              type="info")

            embed = Embed(title="Bloxlink Server-Lock")
            embed.set_footer(text="Powered by Bloxlink",
                             icon_url=Bloxlink.user.avatar_url)
            embed.set_author(name=guild.name, icon_url=guild.icon_url)

            for group_id, data in groups.items():
                embed.add_field(name=f"{data['groupName']} ({group_id})",
                                value=data["dmMessage"],
                                inline=False)

            await response.send(embed=embed)
Example #28
0
    async def __main__(self, CommandArgs):
        author = CommandArgs.author
        response = CommandArgs.response
        prefix = CommandArgs.prefix

        if not SELF_HOST:
            author_data = await self.r.db("bloxlink").table("users").get(str(author.id)).run() or {"id": str(author.id)}

            try:
                primary_account, accounts = await get_user("username", author=author, everything=False, basic_details=True)

                if accounts:
                    parsed_accounts = await parse_accounts(accounts)
                    parsed_accounts_str = ", ".join(parsed_accounts.keys())

                    parsed_args = await CommandArgs.prompt([
                        {
                            "prompt": "This command will allow you to switch into an account you verified as in the past.\n"
                                    f"If you would like to link __a new account__, then please use `{prefix}verify add`.\n\n"
                                    "**__WARNING:__** This will remove __all of your roles__ in the server and give you "
                                    "new roles depending on the server configuration.",
                            "footer": "Say **next** to continue.",
                            "type": "choice",
                            "choices": ["next"],
                            "name": "_",
                            "formatting": False
                        },
                        {
                            "prompt": "Are you trying to change your account for _this_ server? If so, simply say `next`.\nIf not, please provide "
                                    "the __Server ID__ of the server to switch as. Please see this article to find the Server ID: "
                                    "[click here](https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID->).",
                            "name": "guild",
                            "validation": self.validate_server,
                        },
                        {
                            "prompt": "We'll switch your account for the server **{guild.name}**.\n"
                                    "Please select an account to switch into:```" + parsed_accounts_str + "```",
                            "name": "account",
                            "type": "choice",
                            "choices": parsed_accounts.keys()
                        },
                        {
                            "prompt": "Would you like to make this your __primary__ account? Please say **yes** or **no**.",
                            "name": "primary",
                            "type": "choice",
                            "choices": ("yes", "no")
                        }
                    ], last=True)

                    guild = parsed_args["guild"]
                    username = parsed_args["account"]
                    roblox_id = (parsed_accounts.get(username)).id

                    guild_data = await self.r.table("guilds").get(str(guild.id)).run() or {"id": str(guild.id)}

                    trello_board = await get_board(guild_data=guild_data, guild=guild)

                    if trello_board:
                        options_trello, _ = await get_options(trello_board)
                        guild_data.update(options_trello)

                    allow_reverify = guild_data.get("allowReVerify", DEFAULTS.get("allowReVerify"))
                    roblox_accounts = author_data.get("robloxAccounts", {})

                    if guild and not allow_reverify:
                        guild_accounts = roblox_accounts.get("guilds", {})
                        chosen_account = guild_accounts.get(str(guild.id))

                        if chosen_account and chosen_account != roblox_id:
                            raise Error("You already selected your account for this server. `allowReVerify` must be "
                                        "enabled for you to change it.")

                    try:
                        member = await guild.fetch_member(author.id)
                    except (Forbidden, NotFound):
                        await verify_member(author, roblox_id, guild=guild, author_data=author_data, allow_reverify=allow_reverify, primary_account=parsed_args["primary"] == "yes")
                        raise Message("You're not a member of the provided server, so I was only able to update your account internally.", type="success")

                    try:
                        username = await verify_as(
                            member,
                            guild,
                            response     = response,
                            primary      = parsed_args["primary"] == "yes",
                            roblox_id    = roblox_id,
                            trello_board = trello_board,
                            update_user  = False)

                    except Message as e:
                        if e.type == "error":
                            await response.error(e)
                        else:
                            await response.send(e)
                    except Error as e:
                        await response.error(e)
                    else:
                        role_binds, group_ids, _ = await get_binds(guild_data=guild_data, trello_board=trello_board)

                        if count_binds(guild_data, role_binds=role_binds, group_ids=group_ids) and not find(lambda r: r.name == "Bloxlink Bypass", member.roles):
                            for role in list(member.roles):
                                if role != guild.default_role and role.name != "Muted":
                                    try:
                                        await member.remove_roles(role, reason="Switched User")
                                    except Forbidden:
                                        pass
                        try:
                            added, removed, nickname, errors, roblox_user = await update_member(
                                member,
                                guild        = guild,
                                roles        = True,
                                nickname     = True,
                                response     = response,
                                cache        = False)

                        except BloxlinkBypass:
                            await response.info("Since you have the `Bloxlink Bypass` role, I was unable to update your roles/nickname; however, your account was still changed.")

                            return

                        except Blacklisted as b:
                            if str(b):
                                raise Error(f"{author.mention} has an active restriction for: `{b}`.")
                            else:
                                raise Error(f"{author.mention} has an active restriction from Bloxlink.")
                        else:
                            welcome_message = guild_data.get("welcomeMessage") or DEFAULTS.get("welcomeMessage")

                            welcome_message = await get_nickname(author, welcome_message, guild_data=guild_data, roblox_user=roblox_user, is_nickname=False)

                            await post_event(guild, guild_data, "verification", f"{author.mention} ({author.id}) has **switched their user** to `{username}`.", GREEN_COLOR)

                            await CommandArgs.response.send(welcome_message)

                else:
                    raise Message(f"You only have one account linked! Please use `{prefix}verify add` to add another.", type="silly")


            except UserNotVerified:
                raise Error(f"You're not linked to Bloxlink. Please use `{prefix}verify add`.")

        else:
            raise Message(f"{author.mention}, to verify with Bloxlink, please visit our website at " \
                          f"<{VERIFY_URL}>. It won't take long!\nStuck? See this video: <https://www.youtube.com/watch?v=hq496NmQ9GU>")
Example #29
0
    async def change(self, CommandArgs):
        """change your Bloxlink settings"""

        if not CommandArgs.has_permission:
            raise PermissionError("You do not have the required permissions to change server settings.")

        prefix = CommandArgs.prefix
        response = CommandArgs.response

        message = CommandArgs.message
        author = CommandArgs.message.author

        guild = CommandArgs.message.guild
        guild_data = CommandArgs.guild_data

        parsed_args = await CommandArgs.prompt([{
            "prompt": "What value would you like to change? Note that some settings you can't change "
                      "from this command due to the extra complexity, but I will tell you the "
                      f"appropriate command to use.\n\nOptions: ``{options_strings}``\n\nPremium-only options: ``{premium_options_strings}``",
            "name": "choice",
            "type": "choice",
            "formatting": False,
            "footer": f"Use ``{prefix}settings help`` to view a description of all choices.",
            "choices": options_combined
        }])

        choice = parsed_args["choice"]

        if choice == "trelloID":
            raise Message(f"You can link your Trello board from ``{prefix}setup``!", type="success")
        elif choice == "Linked Groups":
            raise Message(f"You can link your group from ``{prefix}bind``!", type="success")
        elif choice == "joinDM":
            message.content = f"{prefix}joindm"
            return await parse_message(message)
        elif choice == "groupShoutChannel":
            message.content = f"{prefix}shoutproxy"
            return await parse_message(message)
        elif choice == "whiteLabel":
            message.content = f"{prefix}whitelabel"
            return await parse_message(message)


        option_find = OPTIONS.get(choice)

        if option_find:
            if option_find[3]:
                profile, _ = await get_features(Object(id=guild.owner_id), guild=guild)

                if not profile.features.get("premium"):
                    raise Error("This option is premium-only! The server owner must have premium for it to be changed.\n"
                                f"Use ``{prefix}donate`` for more instructions on getting premium.")

            option_type = option_find[1]
            trello_board = CommandArgs.trello_board
            card = success_text = parsed_value = None
            desc = option_find[4].format(prefix=CommandArgs.prefix, templates=NICKNAME_TEMPLATES)

            if trello_board:
                options_trello_data, trello_binds_list = await get_options(trello_board, return_cards=True)
                options_trello_find = options_trello_data.get(choice)

                if options_trello_find:
                    card = options_trello_find[1]


            if option_type == "boolean":
                parsed_value = await CommandArgs.prompt([{
                    "prompt": f"Would you like to **enable** or **disable** ``{choice}``?\n\n"
                              f"**Option description:**\n{desc}",
                    "name": "choice",
                    "type": "choice",
                    "footer": "Say **clear** to set as the default value.",
                    "formatting": False,
                    "choices": ("enable", "disable", "clear")
                }])

                parsed_bool_choice = parsed_value["choice"]

                if parsed_bool_choice == "clear":
                    parsed_value = DEFAULTS.get(choice)
                else:
                    parsed_value = parsed_bool_choice == "enable"

                await self.r.table("guilds").insert({
                    "id": str(guild.id),
                    choice: parsed_value
                }, conflict="update").run()

                success_text = f"Successfully **{parsed_bool_choice}d** ``{choice}``!"

            elif option_type == "string":
                parsed_value = (await CommandArgs.prompt([{
                    "prompt": f"Please specify a new value for ``{choice}``.\n\n"
                              f"**Option description:**\n{desc}",
                    "name": "choice",
                    "type": "string",
                    "footer": "Say **clear** to set as the default value.",
                    "formatting": False,
                    "max": option_find[2]
                }]))["choice"]

                if parsed_value == "clear":
                    parsed_value = DEFAULTS.get(choice)

                await self.r.table("guilds").insert({
                    "id": str(guild.id),
                    choice: parsed_value
                }, conflict="update").run()

                success_text = f"Successfully saved your new {choice}!"

            elif option_type == "role":
                parsed_value = (await CommandArgs.prompt([{
                    "prompt": f"Please specify a role for ``{choice}``.\n\n"
                              f"**Option description:**\n{desc}",
                    "name": "role",
                    "type": "role",
                    "exceptions": ("clear",),
                    "footer": "Say **clear** to set as the default value.",
                    "formatting": False
                }]))["role"]

                if parsed_value == "clear":
                    parsed_value = DEFAULTS.get(choice)
                else:
                    parsed_value = str(parsed_value.id)

                await self.r.table("guilds").insert({
                    "id": str(guild.id),
                    choice: parsed_value
                }, conflict="update").run()

                success_text = f"Successfully saved your new ``{choice}``!"

            elif option_type == "number":
                parsed_value = (await CommandArgs.prompt([{
                    "prompt": f"Please specify a new integer for ``{choice}``.\n\n"
                              f"**Option description:**\n{desc}",
                    "name": "choice",
                    "type": "number",
                    "footer": "Say **clear** to set as the default value.",
                    "formatting": False,
                    "exceptions": ("clear",),
                    "max": option_find[2]
                }]))["choice"]

                if parsed_value == "clear":
                    parsed_value = DEFAULTS.get(choice)

                await self.r.table("guilds").insert({
                    "id": str(guild.id),
                    choice: parsed_value
                }, conflict="update").run()

                success_text = f"Successfully saved your new ``{choice}``!"

            elif option_type == "choice":
                choices = ", ".join(option_find[2])
                parsed_value = (await CommandArgs.prompt([{
                    "prompt": f"Please pick a new value for ``{choice}``: ``{choices}``\n\n"
                              f"**Option description:**\n{desc}",
                    "name": "choice",
                    "type": "choice",
                    "footer": "Say **clear** to set as the default value.",
                    "formatting": False,
                    "exceptions": ["clear"],
                    "choices": option_find[2]
                }]))["choice"]

                if parsed_value == "clear":
                    parsed_value = DEFAULTS.get(choice)

                await self.r.table("guilds").insert({
                    "id": str(guild.id),
                    choice: parsed_value
                }, conflict="update").run()

                success_text = f"Successfully saved your new ``{choice}``!"
            else:
                raise Error("An unknown type was specified.")
        else:
            raise Error("An unknown option was specified.")

        if trello_board:
            try:
                if card:
                    if card.name == choice:
                        await card.edit(desc=str(parsed_value))
                    else:
                        await card.edit(name=f"{choice}:{parsed_value}")
                else:
                    trello_settings_list = await trello_board.get_list(lambda L: L.name == "Bloxlink Settings") \
                                           or await trello_board.create_list(name="Bloxlink Settings")

                    await trello_settings_list.create_card(name=choice, desc=str(parsed_value))

                if trello_binds_list:
                    await trello_binds_list.sync(card_limit=TRELLO["CARD_LIMIT"])

            except TrelloUnauthorized:
                await response.error("In order for me to edit your Trello settings, please add ``@bloxlink`` to your "
                                     "Trello board.")

            except (TrelloNotFound, TrelloBadRequest):
                pass

        await set_guild_value(guild, choice, parsed_value)

        await post_event(guild, guild_data, "configuration", f"{author.mention} ({author.id}) has **changed** the ``{choice}`` option.", BROWN_COLOR)

        raise Message(success_text, type="success")
Example #30
0
    async def __main__(self, CommandArgs):
        guild = CommandArgs.guild
        response = CommandArgs.response
        trello_board = CommandArgs.trello_board

        group_id = str(CommandArgs.parsed_args["group_id"])
        role = CommandArgs.parsed_args["role"]
        nickname = CommandArgs.parsed_args["nickname"]
        remove_roles = [
            str(r.id) for r in CommandArgs.parsed_args["remove_roles"]
        ] if (CommandArgs.parsed_args["remove_roles"]
              and CommandArgs.parsed_args["remove_roles"] != "skip") else []
        remove_roles_trello = [
            str(r) for r in CommandArgs.parsed_args["remove_roles"]
        ] if remove_roles and CommandArgs.parsed_args[
            "remove_roles"] != "skip" else []

        nickname_lower = nickname and nickname.lower()
        role_id = str(role.id)

        try:
            group = await get_group(group_id, full_group=False)
        except RobloxNotFound:
            raise Error(
                f"A group with ID `{group_id}` does not exist. Please try again."
            )

        guild_data = CommandArgs.guild_data

        if trello_board:
            trello_binds_list = await trello_board.get_list(
                lambda l: l.name.lower() == "bloxlink binds")

            if not trello_binds_list:
                try:
                    trello_binds_list = await trello_board.create_list(
                        name="Bloxlink Binds")
                except TrelloUnauthorized:
                    await response.error(
                        "In order for me to create Trello binds, please add `@bloxlink` to your "
                        "Trello board.")
                except (TrelloNotFound, TrelloBadRequest):
                    pass

            trello_card_binds, _ = await parse_trello_binds(
                trello_board=trello_board, trello_binds_list=trello_binds_list)
        else:
            trello_binds_list = None
            trello_card_binds = {"groups": {"entire group": {}, "binds": {}}}

        role_binds = guild_data.get("roleBinds") or {}

        if isinstance(role_binds, list):
            role_binds = role_binds[0]

        role_binds["groups"] = role_binds.get("groups") or {
        }  # {"groups": {"ranges": {}, "binds": {}}}
        role_binds["groups"][group_id] = role_binds["groups"].get(
            group_id) or {}
        role_binds["groups"][group_id][
            "binds"] = role_binds["groups"][group_id].get("binds") or {}

        x = "0"

        rank = role_binds["groups"][group_id].get("binds", {}).get(x, {})

        if not isinstance(rank, dict):
            rank = {
                "nickname":
                nickname if nickname and nickname_lower not in ("skip", "done")
                else None,
                "roles": [str(rank)],
                "removeRoles":
                remove_roles
            }

            if role_id not in rank["roles"]:
                rank["roles"].append(role_id)
        else:
            if role_id not in rank.get("roles", []):
                rank["roles"] = rank.get("roles") or []
                rank["roles"].append(role_id)

            if nickname and nickname_lower not in ("skip", "done"):
                rank["nickname"] = nickname
            else:
                if not rank.get("nickname"):
                    rank["nickname"] = None

            rank["removeRoles"] = remove_roles

        role_binds["groups"][group_id]["binds"][x] = rank

        if trello_binds_list:
            make_binds_card = True

            if trello_card_binds:
                trello_bind_group = trello_card_binds["groups"]["binds"].get(
                    group_id, {}).get("binds")

                if trello_bind_group:
                    card_data_ = trello_bind_group.get(x)
                    if card_data_:
                        for card in card_data_["trello"]["cards"]:
                            trello_card = card["card"]
                            trello_ranks = card.get("ranks", [])

                            if (x in trello_ranks
                                    or x == "all") and len(trello_ranks) == 1:
                                trello_bind_roles = card.get("roles", set())
                                card_bind_data = [
                                    f"Group: {group_id}",
                                    f"Nickname: {(nickname != 'skip' and nickname) or rank.get('nickname') or card_data_.get('nickname') or 'None'}",
                                ]

                                if remove_roles:
                                    card_bind_data.append(
                                        f"Remove roles: {', '.join(remove_roles_trello)}"
                                    )

                                for role_ in trello_bind_roles:
                                    if role_ in (role_id, role.name):
                                        break
                                else:
                                    trello_bind_roles.add(role.name)
                                    card_bind_data.append(
                                        f"Roles: {', '.join(trello_bind_roles)}"
                                    )

                                card_bind_data.append(
                                    f"Ranks: {card['trello_str']['ranks']}")

                                trello_card_desc = "\n".join(card_bind_data)

                                if trello_card_desc != trello_card.description:
                                    trello_card.description = trello_card_desc

                                    try:
                                        await trello_card.edit(
                                            desc=trello_card_desc)
                                    except TrelloUnauthorized:
                                        await response.error(
                                            "In order for me to edit your Trello binds, please add `@bloxlink` to your "
                                            "Trello board.")
                                    except (TrelloNotFound, TrelloBadRequest):
                                        pass

                                    trello_binds_list.parsed_bind_data = None
                                    make_binds_card = False

                                    break

            if make_binds_card:
                card_bind_data = [
                    f"Group: {group_id}",
                    f"Nickname: {nickname != 'skip' and nickname or 'None'}",
                    f"Roles: {role.name}",
                ]

                if remove_roles:
                    card_bind_data.append(
                        f"Remove roles: {', '.join(remove_roles_trello)}")

                if x != "all":
                    card_bind_data.append(f"Ranks: {x}")

                trello_card_desc = "\n".join(card_bind_data)

                try:
                    card = await trello_binds_list.create_card(
                        name="Bloxlink Bind", desc=trello_card_desc)
                except TrelloUnauthorized:
                    await response.error(
                        "In order for me to edit your Trello binds, please add `@bloxlink` to your "
                        "Trello board.")
                except (TrelloNotFound, TrelloBadRequest):
                    pass

                trello_binds_list.parsed_bind_data = None

        await self.r.table("guilds").insert(
            {
                "id": str(guild.id),
                "roleBinds": role_binds
            }, conflict="update").run()

        await response.success(
            f"Successfully bound this **Guest Role** to role **{role.name}!**")