Exemplo n.º 1
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")
Exemplo n.º 2
0
    async def __main__(self, CommandArgs):
        response   = CommandArgs.response
        action     = CommandArgs.parsed_args["action"]
        guild      = CommandArgs.guild
        author     = CommandArgs.author
        locale     = CommandArgs.locale
        guild_data = CommandArgs.guild_data
        prefix     = CommandArgs.prefix

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

            if 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(locale("scans.queued"))
                    elif on_cooldown == 2:
                        raise Message(locale("scans.running"))
                    elif on_cooldown == 3:
                        cooldown_time = math.ceil(await self.redis.ttl(redis_cooldown_key)/60)

                        raise Message(locale("scans.cooldown", cooldown=cooldown_time))

            await self.redis.set(redis_cooldown_key, 1, ex=86400)
            await self.process_guild(guild_data, guild, author, action, response, locale, prefix)
Exemplo n.º 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}!**")
Exemplo n.º 4
0
    async def disable(self, CommandArgs):
        """disable your Bloxlink premium transfer"""

        author = CommandArgs.author
        guild = CommandArgs.guild
        response = CommandArgs.response

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

        author_data_premium = author_data.get("premium", {})
        transfer_to = author_data_premium.get("transferTo")

        if not transfer_to:
            transfer_from = author_data_premium.get("transferFrom")

            if not transfer_from:
                raise Message("You've not received a premium transfer!", type="confused")

            # clear original transferee and recipient data
            transferee_data = await self.r.db("bloxlink").table("users").get(transfer_from).run() or {"id": transfer_from}
            transferee_data_premium = transferee_data.get("premium", {})

            author_data_premium["transferFrom"] = None
            transferee_data_premium["transferTo"] = None

            author_data["premium"] = author_data_premium
            transferee_data["premium"] = transferee_data_premium

            await self.r.db("bloxlink").table("users").insert(author_data, conflict="update").run()
            await self.r.db("bloxlink").table("users").insert(transferee_data, conflict="update").run()

            await cache_pop(f"premium_cache:{author.id}")
            await cache_pop(f"premium_cache:{transfer_from}")
            await cache_pop(f"premium_cache:{guild.id}")

            raise Message("Successfully **disabled** the premium transfer!", type="success")

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

            author_data_premium["transferTo"] = None
            recipient_data_premium["transferFrom"] = None

            author_data["premium"] = author_data_premium
            recipient_data["premium"] = recipient_data_premium

            await self.r.db("bloxlink").table("users").insert(author_data, conflict="update").run()
            await self.r.db("bloxlink").table("users").insert(recipient_data, conflict="update").run()

            await cache_pop(f"premium_cache:{author.id}")
            await cache_pop(f"premium_cache:{transfer_to}")
            await cache_pop(f"premium_cache:{guild.id}")

            await response.success("Successfully **disabled** your premium transfer!")
Exemplo n.º 5
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
Exemplo n.º 6
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)
Exemplo n.º 7
0
    async def view(self, CommandArgs):
        """view your log channels"""

        guild = CommandArgs.guild
        guild_data = CommandArgs.guild_data

        log_channels = guild_data.get("logChannels") or {}

        response = CommandArgs.response

        if not log_channels:
            raise Message("You have no log channels!", type="silly")

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

        description = []

        for log_type, log_channel_id in log_channels.items():
            log_channel = guild.get_channel(int(log_channel_id))
            description.append(
                f"`{log_type}` {ARROW} {log_channel and log_channel.mention or '(Deleted)'}"
            )

        embed.description = "\n".join(description)

        await response.send(embed=embed)
Exemplo n.º 8
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!")
Exemplo n.º 9
0
    async def unverified(self, CommandArgs):
        """set the DM message of people who are UNVERIFIED on Bloxlink"""

        author = CommandArgs.author
        guild = CommandArgs.guild
        guild_data = CommandArgs.guild_data
        unverifiedDM = guild_data.get("unverifiedDM")

        response = CommandArgs.response

        if unverifiedDM:
            response.delete(await response.send(
                "When people join your server and are **UNVERIFIED** on Bloxlink, they will "
                f"receive this DM:"))
            response.delete(await response.send(f"```{unverifiedDM}```"))

        parsed_args_1 = (await CommandArgs.prompt([{
            "prompt":
            "Would you like to **change** the DM people get when they join and are unverified, or "
            "would you like to **disable** this feature?\n\nPlease specify: (change, disable)",
            "name":
            "option",
            "type":
            "choice",
            "choices": ("change", "disable")
        }]))["option"]

        if parsed_args_1 == "change":
            parsed_args_2 = (await CommandArgs.prompt([{
                "prompt":
                "What would you like the text of the Unverified Join DM to be? You may use "
                f"these templates: ```{UNVERIFIED_TEMPLATES}```",
                "name":
                "text",
                "formatting":
                False
            }],
                                                      last=True))["text"]

            guild_data["unverifiedDM"] = parsed_args_2
            await set_guild_value(guild, "unverifiedDM", parsed_args_2)

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

        elif parsed_args_1 == "disable":
            guild_data["unverifiedDM"] = None
            await set_guild_value(guild, "unverifiedDM", None)

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

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

        raise Message(f"Successfully **{parsed_args_1}d** your DM message.",
                      type="success")
Exemplo n.º 10
0
    async def backup(self, CommandArgs):
        """backup your Server Data"""

        author = CommandArgs.author
        guild = CommandArgs.guild
        response = CommandArgs.response

        author_id = str(author.id)

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

        if len(user_backups) >= LIMITS["BACKUPS"]:
            response.delete(await response.info(
                "You've exceeded the amount of backups you're able to create! Your next "
                "backup will replace your oldest backup."))
            user_backups.pop(0)

        parsed_args = await CommandArgs.prompt([{
            "prompt":
            "**Warning!** This will backup **all** of your Server Data, including "
            "Linked Groups, Role Binds, prefixes, etc to restore to a different server.\n"
            f"You are allowed to create **{LIMITS['BACKUPS']}** total backups for **all of your servers.**",
            "name":
            "_",
            "embed_title":
            "Warning!",
            "embed_color":
            ORANGE_COLOR,
            "footer":
            "Say anything to continue."
        }, {
            "prompt":
            "What would you like to name this backup? You may use up to 30 characters.",
            "name": "backup_name",
            "max": 30
        }],
                                               last=True)

        backup_name = parsed_args["backup_name"]

        new_backup = await self._backup(guild, backup_name)

        if new_backup:
            user_backups.append(new_backup)
        else:
            raise Message(
                "There's nothing to save - your server has no saved data!",
                type="silly")

        user_data["backups"] = user_backups

        await self.r.db("bloxlink").table("users").insert(
            user_data, conflict="update").run()

        await response.success("Successfully saved your new backup!")
Exemplo n.º 11
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)
Exemplo n.º 12
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)
Exemplo n.º 13
0
    async def view(CommandArgs):
        """view your linked account(s)"""

        author = CommandArgs.author
        response = CommandArgs.response

        try:
            primary_account, accounts = await get_user("username",
                                                       author=author,
                                                       everything=False,
                                                       basic_details=True)
        except UserNotVerified:
            raise Message("You have no accounts linked to Bloxlink!",
                          type="silly")
        else:
            accounts = list(accounts)

            parsed_accounts = await parse_accounts(accounts,
                                                   reverse_search=True)
            parsed_accounts_str = []
            primary_account_str = "No primary account set"

            for roblox_username, roblox_data in parsed_accounts.items():
                if roblox_data[1]:
                    username_str = []

                    for discord_account in roblox_data[1]:
                        username_str.append(
                            f"{discord_account} ({discord_account.id})")

                    username_str = ", ".join(username_str)

                    if primary_account and roblox_username == primary_account.username:
                        primary_account_str = f"**{roblox_username}** {ARROW} {username_str}"
                    else:
                        parsed_accounts_str.append(
                            f"**{roblox_username}** {ARROW} {username_str}")

                else:
                    parsed_accounts_str.append(f"**{roblox_username}**")

            parsed_accounts_str = "\n".join(parsed_accounts_str)

            embed = Embed(title="Linked Roblox Accounts")
            embed.add_field(name="Primary Account", value=primary_account_str)
            embed.add_field(name="Secondary Accounts",
                            value=parsed_accounts_str
                            or "No secondary account saved")
            embed.set_author(name=author, icon_url=author.avatar_url)

            await response.send(embed=embed,
                                dm=True,
                                hidden=False,
                                strict_post=True)
Exemplo n.º 14
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.")
Exemplo n.º 15
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)
Exemplo n.º 16
0
    async def verified(self, CommandArgs):
        """set the DM message of people who are VERIFIED on Bloxlink"""

        author = CommandArgs.author
        guild = CommandArgs.guild

        verified_DM = await get_guild_value(
            guild, ["verifiedDM", DEFAULTS.get("welcomeMessage")])

        response = CommandArgs.response

        if verified_DM:
            response.delete(await response.send(
                "When people join your server and are **VERIFIED** on Bloxlink, they will "
                f"receive this DM:"))
            response.delete(await response.send(f"```{verified_DM}```"))

        parsed_args_1 = (await CommandArgs.prompt([{
            "prompt":
            "Would you like to **change** the DM people get when they join and are verified, or "
            "would you like to **disable** this feature?\n\nPlease specify: (change, disable)",
            "name":
            "option",
            "type":
            "choice",
            "choices": ("change", "disable")
        }]))["option"]

        if parsed_args_1 == "change":
            parsed_args_2 = (await CommandArgs.prompt([{
                "prompt":
                "What would you like the text of the Verified Join DM to be? You may use "
                f"these templates: ```{NICKNAME_TEMPLATES}```",
                "name":
                "text",
                "formatting":
                False
            }],
                                                      last=True))["text"]

            await set_guild_value(guild, verifiedDM=parsed_args_2)

        elif parsed_args_1 == "disable":
            await set_guild_value(guild, verifiedDM=None)

        await post_event(
            guild, "configuration",
            f"{author.mention} ({author.id}) has **changed** the `joinDM` option for `verified` members.",
            BROWN_COLOR)

        raise Message(f"Successfully **{parsed_args_1}d** your DM message.",
                      type="success")
Exemplo n.º 17
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.")
Exemplo n.º 18
0
    async def unverified(self, CommandArgs):
        """set the join message of people who are UNVERIFIED on Bloxlink"""

        guild_data = CommandArgs.guild_data
        join_channel = guild_data.get("joinChannel") or {}
        unverified_message = join_channel.get("unverified")

        author = CommandArgs.author
        guild = CommandArgs.guild

        response = CommandArgs.response

        if unverified_message:
            response.delete(await response.send(
                "When people join your server and are **UNVERIFIED** on Bloxlink, this message "
                "will be posted:"))
            response.delete(
                await response.send(f"```{unverified_message['message']}```"))

        parsed_args_1 = (await CommandArgs.prompt([{
            "prompt":
            "Would you like to **change** the message people get when they join and are unverified, or "
            "would you like to **disable** this feature?",
            "name":
            "option",
            "type":
            "choice",
            "components": [
                discord.ui.Select(
                    max_values=1,
                    options=[
                        discord.SelectOption(
                            label="Change message",
                            description=
                            "Change the message for unverified users."),
                        discord.SelectOption(
                            label="Disable",
                            description="No join message for unverified users."
                        ),
                    ])
            ],
            "choices": ("Change message", "Disable")
        }]))["option"][0]

        if parsed_args_1 == "Change message":
            parsed_args_2 = await CommandArgs.prompt([{
                "prompt":
                "What would you like the text of the Unverified Join Message to be? You may use "
                f"these templates: ```{UNVERIFIED_TEMPLATES}```",
                "name":
                "text",
                "max":
                1500,
                "formatting":
                False
            }, {
                "prompt":
                "Which **channel** would you like the join messages to be posted in?",
                "name": "channel",
                "type": "channel"
            }, {
                "prompt":
                "Would you like to keep the join messages in an embed format, or keep it as text?\nIt's "
                "recommended to say `embed` if you chose to include avatars for the `verified` message "
                "so the verified and unverified join messages look similar.",
                "components": [
                    discord.ui.Select(
                        max_values=1,
                        options=[
                            discord.SelectOption(
                                label="Use embed format",
                                description=
                                "The join message will be in an embed."),
                            discord.SelectOption(
                                label="Use text format",
                                description=
                                "The join message will be in a standard message."
                            ),
                        ])
                ],
                "name":
                "type",
                "type":
                "choice",
                "choices": ("Use embed format", "Use text format")
            }],
                                                     last=True)

            channel = parsed_args_2["channel"]
            text = parsed_args_2["text"]
            embed_format = parsed_args_2["type"][0] == "Use embed format"
            includes = {}

            parsed_args_3 = await CommandArgs.prompt([
                {
                    "prompt":
                    "Would you like this join message to ping people?",
                    "name":
                    "ping",
                    "type":
                    "choice",
                    "components": [
                        discord.ui.Select(
                            max_values=1,
                            options=[
                                discord.SelectOption(
                                    label="Ping people",
                                    description="The message will ping people."
                                ),
                                discord.SelectOption(
                                    label="Don't ping people",
                                    description=
                                    "The message will NOT ping anyone."),
                            ])
                    ],
                    "choices": ("Ping people", "Don't ping people")
                },
            ],
                                                     last=True)

            if parsed_args_3["ping"][0] == "Ping people":
                includes["ping"] = True

            join_channel["unverified"] = {
                "channel": str(channel.id),
                "message": text,
                "includes": includes,
                "embed": embed_format
            }
            guild_data["joinChannel"] = join_channel

            await set_guild_value(guild, "joinChannel", join_channel)

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

        else:
            join_channel.pop("unverified", None)
            guild_data["joinChannel"] = join_channel

            await set_guild_value(guild, "joinChannel", join_channel)

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

        change_text = f"**{'changed' if parsed_args_1 == 'Change message' else 'disabled'}**"

        await post_event(
            guild, guild_data, "configuration",
            f"{author.mention} ({author.id}) has {change_text} the `joinChannel` option for `verified` members.",
            BROWN_COLOR)

        raise Message(f"Successfully {change_text} your join message.",
                      type="success")
Exemplo n.º 19
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")
Exemplo n.º 20
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.")
Exemplo n.º 21
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)
Exemplo n.º 22
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>")
Exemplo n.º 23
0
    async def reset(self, CommandArgs):
        """reset either ALL of your settings, or just your binds"""

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

        prefix = CommandArgs.prefix
        response = CommandArgs.response
        trello_board = CommandArgs.trello_board

        author = CommandArgs.message.author

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


        parsed_arg = (await CommandArgs.prompt([{
            "prompt": f"Which setting would you like to clear? Valid choices: ``{RESET_CHOICES}``",
            "name": "choice",
            "type": "choice",
            "formatting": False,
            "choices": RESET_CHOICES
        }]))["choice"]

        if parsed_arg == "everything":
            cont = (await CommandArgs.prompt([{
                "prompt": "**Warning!** This will clear **all of your settings** including binds, "
                          f"saved group information, etc. You'll need to run ``{prefix}setup`` "
                           "and set-up the bot again. Continue? ``Y/N``",
                "name": "continue",
                "choices": ("yes", "no"),
                "embed_title": "Warning!",
                "embed_color": ORANGE_COLOR,
                "type": "choice",
                "footer": "Say **yes** to clear all of your settings, or **no** to cancel."
            }]))["continue"]

            if cont == "no":
                raise CancelledPrompt

            await self.r.table("guilds").get(str(guild.id)).delete().run()

            if trello_board:
                trello_options, _ = await get_options(trello_board, return_cards=True)

                try:
                    if trello_options:
                        for option_name, option in trello_options.items():
                            await option[1].archive()

                    trello_binds_list = await trello_board.get_list(lambda l: l.name == "Bloxlink Binds")

                    if trello_binds_list:
                        for card in await trello_binds_list.get_cards(limit=TRELLO["CARD_LIMIT"]):
                            await card.archive()

                        trello_binds_list.parsed_bind_data = None

                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
                else:
                    await trello_board.sync(card_limit=TRELLO["CARD_LIMIT"], list_limit=TRELLO["LIST_LIMIT"])


            await post_event(guild, guild_data, "configuration", f"{author.mention} ({author.id}) has **deleted** all server information.", BROWN_COLOR)

            await clear_guild_data(guild)

            raise Message("Your server information was successfully cleared.", type="success")


        elif parsed_arg == "binds":
            # delete all binds from db and trello

            cont = (await CommandArgs.prompt([{
                "prompt": "**Warning!** This will clear **all of your binds**. You'll need to "
                         f"run ``{prefix}bind`` to set up your binds again. Continue? ``Y/N``",
                "name": "continue",
                "choices": ("yes", "no"),
                "type": "choice",
                "embed_title": "Warning!",
                "embed_color": ORANGE_COLOR,
                "formatting": False,
                "footer": "Say **yes** to clear all of your binds, or **no** to cancel."
            }]))["continue"]

            if cont == "no":
                raise CancelledPrompt

            guild_data = CommandArgs.guild_data
            role_binds = guild_data.get("roleBinds", {})

            if role_binds:
                role_ids = set()

                for group_id, group_data in role_binds.get("groups", {}).items():
                    for rank_id, rank_data in group_data.get("binds", {}).items():
                        for role_id in rank_data["roles"]:
                            role_ids.add(int(role_id))

                    for range_data in group_data.get("ranges", []):
                        if range_data["roles"]:
                            for role_id in range_data["roles"]:
                                role_ids.add(int(role_id))


                if role_ids:
                    delete_roles = (await CommandArgs.prompt([{
                        "prompt": "Would you like me to **delete these roles from your server as well?** If yes, "
                                  f"then this will delete **{len(role_ids)}** role(s). ``Y/N``",
                        "name": "delete_roles",
                        "choices": ("yes", "no"),
                        "type": "choice",
                        "embed_title": "Warning!",
                        "embed_color": ORANGE_COLOR,
                        "formatting": False,
                        "footer": "Say **yes** to delete these roles, or **no** to cancel."
                    }]))["delete_roles"]

                    if delete_roles == "yes":
                        for role_id in role_ids:
                            role = guild.get_role(role_id)

                            if role:
                                try:
                                    await role.delete(reason=f"{author} chose to delete bound roles through {prefix}settings")
                                except Forbidden:
                                    pass

                        await response.success("Your bound roles were deleted.")

            guild_data.pop("roleBinds", None)
            guild_data.pop("groupIDs", None)

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

            if trello_board:
                try:
                    trello_binds_list = await trello_board.get_list(lambda l: l.name == "Bloxlink Binds")

                    if trello_binds_list:
                        for card in await trello_binds_list.get_cards(limit=TRELLO["CARD_LIMIT"]):
                            await card.archive()

                        trello_binds_list.parsed_bind_data = None

                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
                else:
                    await trello_board.sync(card_limit=TRELLO["CARD_LIMIT"], list_limit=TRELLO["LIST_LIMIT"])


            await post_event(guild, guild_data, "configuration", f"{author.mention} ({author.id}) has **deleted** all binds.", BROWN_COLOR)

            await clear_guild_data(guild)

            raise Message("Successfully **cleared** all of your bound roles.", type="success")
Exemplo n.º 24
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")
Exemplo n.º 25
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])}!**")
Exemplo n.º 26
0
    async def change(self, CommandArgs):
        """add/delete a log channel"""

        prefix = CommandArgs.prefix
        response = CommandArgs.response
        guild_data = CommandArgs.guild_data

        author = CommandArgs.author
        guild = CommandArgs.guild

        log_channels = guild_data.get("logChannels") or {}

        parsed_args = await CommandArgs.prompt([{
            "prompt":
            "Please select an **event** to add/delete:\n"
            "`all` " + ARROW + " all events will be sent to your channel\n"
            "`verifications` " + ARROW + " user verifications will be logged "
            "to your channel\n"
            "`configurations` " + ARROW +
            " any Bloxlink setting alteration will be "
            "logged to your channel\n"
            "`inactivity notices` _(premium)_ " + ARROW +
            " user-set inactivity notices "
            "from `" + prefix + "profie` will "
            "be logged to your channel\n"
            "`binds` " + ARROW +
            " bind insertions/deletions will be logged to your channel\n"
            "`moderation` " + ARROW +
            " automatic moderation actions by certain features will be "
            "logged to your channel",
            "name":
            "log_type",
            "type":
            "choice",
            "choices": [
                "all", "verifications", "configurations", "inactivity notices",
                "binds", "moderation"
            ]
        }, {
            "prompt":
            "Please either **mention a channel**, or say a **channel name.**\n"
            "Successful `{log_type}` events will be posted to this channel.\n\n"
            "**Please make sure Bloxlink has permission to send/read messages "
            "from the channel!**",
            "name":
            "log_channel",
            "footer":
            "Say **clear** to **delete** an already existing log channel of this type.",
            "type":
            "channel",
            "exceptions": ["clear", "delete"]
        }],
                                               last=True)

        log_type = parsed_args["log_type"]

        if log_type.endswith("s"):
            log_type = log_type[:
                                -1]  # remove ending "s" - looks better on embed titles

        log_channel = parsed_args["log_channel"]
        action = None

        if log_type == "inactivity notices":
            donator_profile, _ = await get_features(Object(id=guild.owner_id),
                                                    guild=guild)

            if not donator_profile.features.get("premium"):
                raise Message(
                    "Only premium subscribers can subscribe to `inactivity notices`!\n"
                    f"Please use `{prefix}donate` for instructions on subscribing to premium.",
                    type="silly")

        if log_channel in ("clear", "delete"):
            log_channels.pop(log_type, None)
            action = "deleted"
        else:
            log_channels[log_type] = str(log_channel.id)
            action = "saved"

        if not log_channels:
            guild_data.pop("logChannels", None)
        else:
            guild_data["logChannels"] = log_channels

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

        await set_guild_value(guild, "logChannels", log_channels)

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

        await response.success(f"Successfully **{action}** your log channel!")
Exemplo n.º 27
0
    async def __main__(self, CommandArgs):
        guild = CommandArgs.guild

        guild_data = CommandArgs.guild_data
        trello_board = CommandArgs.trello_board
        prefix = CommandArgs.prefix

        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) == 0:
            raise Message(
                f"You have no bounded roles! Please use `{CommandArgs.prefix}bind` "
                "to make a new role bind.",
                type="silly")

        embed = Embed(title="Bloxlink Role Binds")

        text = []
        if group_ids:
            for group_id, group_data in group_ids.items():
                text.append(
                    f"**Group:** {group_data['groupName']} ({group_id}) {ARROW} **Nickname:** {group_data['nickname']}"
                )

            text = "\n".join(text)

            embed.add_field(name="Linked Groups", value=text, inline=False)

        if role_binds:
            role_cache = {}

            for category, bind_data in role_binds.items():
                if category == "groups":
                    for group_id, group_data in bind_data.items():
                        text = []
                        for rank_id, rank_data in group_data.get("binds",
                                                                 {}).items():
                            role_names = set()

                            if rank_data["roles"]:
                                for role_ in rank_data["roles"]:
                                    role_cache_find = role_cache.get(role_)

                                    if role_cache_find:
                                        role_names.add(role_cache_find)
                                    else:
                                        for role in guild.roles:
                                            if role_ in (role.name,
                                                         str(role.id)):
                                                role_names.add(role.name)
                                                role_cache[role_] = role.name

                                                break
                                        else:
                                            try:
                                                int(role_)
                                            except ValueError:
                                                role_names.add(role_)
                                                role_cache[role_] = role_
                                            else:
                                                # deleted role
                                                # TODO: check if the role is saved in server settings, then delete it
                                                role_names.add(
                                                    "(Deleted Role(s))")
                                                role_cache[
                                                    role_] = "(Deleted Role(s))"

                                if rank_id in ("guest", "0"):
                                    text.append(
                                        f"**Rank:** (Guest Role) {ARROW} **Roles:** {', '.join(role_names)} {ARROW} **Nickname:** {rank_data['nickname']}"
                                    )
                                else:
                                    text.append(
                                        f"**Rank:** {rank_id} {ARROW} **Roles:** {', '.join(role_names)} {ARROW} **Nickname:** {rank_data['nickname']}"
                                    )
                            else:
                                text.append(
                                    f"**Rank:** {rank_id} {ARROW} **Roles:** (Dynamic Roles) {ARROW} **Nickname:** {rank_data['nickname']}"
                                )

                        for range_data in group_data.get("ranges", []):
                            role_names = set()

                            if range_data["roles"]:
                                for role_ in range_data["roles"]:
                                    role_cache_find = role_cache.get(role_)

                                    if role_cache_find:
                                        role_names.add(role_cache_find)
                                    else:
                                        for role in guild.roles:
                                            if role_ in (role.name,
                                                         str(role.id)):
                                                role_names.add(role.name)
                                                role_cache[role_] = role.name

                                                break
                                        else:
                                            try:
                                                int(role_)
                                            except ValueError:
                                                role_names.add(role_)
                                                role_cache[role_] = role_
                                            else:
                                                # deleted role
                                                # TODO: check if the role is saved in server settings, then delete it
                                                role_names.add(
                                                    "(Deleted Role(s))")
                                                role_cache[
                                                    role_] = "(Deleted Role(s))"

                                text.append(
                                    f"**Rank Range:** {range_data['low']} - {range_data['high']} {ARROW} **Roles:** {', '.join(role_names)} {ARROW} **Nickname:** {range_data['nickname']}"
                                )
                            else:
                                text.append(
                                    f"**Rank Range:** {range_data['low']} - {range_data['high']} {ARROW} **Roles:** (Dynamic Roles) {ARROW} **Nickname:** {range_data['nickname']}"
                                )

                        if text:
                            text = "\n".join(text)

                            try:
                                group_name = group_data.get("groupName") or (
                                    await get_group(group_id,
                                                    full_group=True)).name
                            except RobloxNotFound:
                                # TODO: remove group
                                pass
                            else:
                                embed.add_field(
                                    name=f"{group_name} ({group_id})",
                                    value=text,
                                    inline=False)

                else:
                    text = []

                    if category == "gamePasses":
                        category_non_plural = "gamePass"
                        category_non_plural_title = "GamePass"
                        category_title = "GamePasses"
                    elif category == "devForum":
                        category_title = "DevForum Members"
                    elif category == "robloxStaff":
                        category_title = "Roblox Staff"
                    else:
                        category_non_plural = category[:-1]
                        category_non_plural_title = category_non_plural.title()
                        category_title = category.title()

                    if category in ("devForum", "robloxStaff"):
                        role_names = set()

                        if bind_data["roles"]:
                            for role_ in bind_data["roles"]:
                                role_cache_find = role_cache.get(role_)

                                if role_cache_find:
                                    role_names.add(role_cache_find)
                                else:
                                    for role in guild.roles:
                                        if role_ in (role.name, str(role.id)):
                                            role_names.add(role.name)
                                            role_cache[role_] = role.name

                                            break
                                    else:
                                        try:
                                            int(role_)
                                        except ValueError:
                                            role_names.add(role_)
                                            role_cache[role_] = role_
                                        else:
                                            # deleted role
                                            # TODO: check if the role is saved in server settings, then delete it
                                            role_names.add("(Deleted Role(s))")
                                            role_cache[
                                                role_] = "(Deleted Role(s))"

                            text.append(
                                f"**Roles:** {', '.join(role_names)} {ARROW} **Nickname:** {bind_data['nickname']}"
                            )

                        else:
                            text.append(
                                f"**Roles:** (No Roles) {ARROW} **Nickname:** {bind_vg_data['nickname']}"
                            )
                    else:
                        for bind_id, bind_vg_data in bind_data.items():
                            display_name = bind_vg_data.get(
                                "displayName") or "(No Name)"
                            role_names = set()

                            if bind_vg_data["roles"]:
                                for role_ in bind_vg_data["roles"]:
                                    role_cache_find = role_cache.get(role_)

                                    if role_cache_find:
                                        role_names.add(role_cache_find)
                                    else:
                                        for role in guild.roles:
                                            if role_ in (role.name,
                                                         str(role.id)):
                                                role_names.add(role.name)
                                                role_cache[role_] = role.name

                                                break
                                        else:
                                            try:
                                                int(role_)
                                            except ValueError:
                                                role_names.add(role_)
                                                role_cache[role_] = role_
                                            else:
                                                # deleted role
                                                # TODO: check if the role is saved in server settings, then delete it
                                                role_names.add(
                                                    "(Deleted Role(s))")
                                                role_cache[
                                                    role_] = "(Deleted Role(s))"

                                text.append(
                                    f"**{category_non_plural_title}:** {display_name} ({bind_id}) {ARROW} **Roles:** {', '.join(role_names)} {ARROW} **Nickname:** {bind_vg_data['nickname']}"
                                )

                            else:
                                text.append(
                                    f"**{category_non_plural_title}:** {display_name} ({bind_id}) {ARROW} **Roles:** (No Roles) {ARROW} **Nickname:** {bind_vg_data['nickname']}"
                                )

                    if text:
                        text = "\n".join(text)
                        embed.add_field(name=category_title,
                                        value=text,
                                        inline=False)

        embed.set_author(name="Powered by Bloxlink",
                         icon_url=Bloxlink.user.avatar.url)
        embed.set_footer(
            text=
            f"Use {prefix}bind to make a new bind, or {prefix}delbind to delete a bind"
        )

        await CommandArgs.response.send(embed=embed)
Exemplo n.º 28
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

        if not guild:
            return await self.add(CommandArgs)

        if CommandArgs.flags.get("add") or CommandArgs.flags.get(
                "verify") or CommandArgs.flags.get("force"):
            await CommandArgs.response.error(
                f"`{CommandArgs.prefix}verify --force` is deprecated and will be removed in a future version of Bloxlink. "
                f"Please use `{prefix}verify add` instead.")

            return await self.add(CommandArgs)

        if CommandArgs.real_command_name in ("getrole", "getroles"):
            CommandArgs.string_args = []

        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, roblox_user = await guild_obligations(
                CommandArgs.author,
                guild=guild,
                guild_data=guild_data,
                roles=True,
                nickname=True,
                trello_board=CommandArgs.trello_board,
                given_trello_options=True,
                cache=False,
                response=response,
                dm=False,
                exceptions=("BloxlinkBypass", "Blacklisted", "UserNotVerified",
                            "PermissionError"))

        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 self.add(CommandArgs)

        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,
                nickname=nickname
                if old_nickname != author.display_name else None,
                prefix=prefix,
                guild_data=guild_data)

            if embed:
                await post_event(
                    guild, guild_data, "verification",
                    f"{author.mention} ({author.id}) has **verified** as `{roblox_user.username}`.",
                    GREEN_COLOR)
            else:
                embed = Embed(
                    description=
                    "This user is all up-to-date; no changes were made.")

            await response.send(content=welcome_message, embed=embed)
Exemplo n.º 29
0
    async def __main__(self, CommandArgs):
        response = CommandArgs.response
        command = CommandArgs.command

        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)

        author = CommandArgs.author
        guild = CommandArgs.guild

        users = []

        if not (users_ and CommandArgs.has_permission):
            if not users_:
                await command.redirect(CommandArgs, "getrole")
                raise CancelCommand
            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 not guild.chunked:
            await guild.chunk()

        if users_[1]:
            role = users_[1]

            users += role.members

            if not users:
                raise Error("This role has no members in it!", hidden=True)

        if users_[0]:
            user = users_[0]
            users.append(user)

        len_users = len(users)

        for i, user in enumerate(users):
            if isinstance(user, User):
                try:
                    user = await guild.fetch_member(user.id)
                except NotFound:
                    raise Error("This user isn't in your server!")
                else:
                    users[i] = user

        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 has_premium(guild=guild)
            premium = "premium" in donator_profile.features

            if not premium:
                donator_profile = await has_premium(user=author)
                premium = "premium" in donator_profile.features

            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 `/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)

            #async with response.loading():
            if len_users > 1:
                await response.send(f"Updating **{len_users}** users...")

                for user in users:
                    if not user.bot:
                        try:
                            added, removed, nickname, errors, warnings, roblox_user = await guild_obligations(
                                user,
                                guild=guild,
                                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."
                                )
                        except CancelCommand:
                            pass
                        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,
                        roles=True,
                        nickname=True,
                        cache=False,
                        dm=False,
                        event=True,
                        exceptions=("BloxlinkBypass", "Blacklisted",
                                    "CancelCommand", "UserNotVerified",
                                    "PermissionError", "RobloxDown",
                                    "RobloxAPIError"))

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

                    message = await response.send(
                        embed=embed,
                        files=[card.front_card_file] if card else None,
                        view=card.view if card else None)

                    if card:
                        card.response = response
                        card.message = message
                        card.view.message = message

                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.")
Exemplo n.º 30
0
    async def verified(self, CommandArgs):
        """set the join message of people who are VERIFIED on Bloxlink"""

        guild_data = CommandArgs.guild_data
        join_channel = guild_data.get("joinChannel") or {}
        verified_message = join_channel.get("verified")

        author = CommandArgs.author
        guild = CommandArgs.guild

        response = CommandArgs.response

        if verified_message:
            response.delete(await response.send(
                "When people join your server and are **VERIFIED** on Bloxlink, this message "
                "will be posted:"))
            response.delete(
                await response.send(f"```{verified_message['message']}```"))

        parsed_args_1 = (await CommandArgs.prompt([{
            "prompt":
            "Would you like to **change** the message people get when they join and are verified, or "
            "would you like to **disable** this feature?",
            "name":
            "option",
            "type":
            "choice",
            "components": [
                discord.ui.Select(
                    max_values=1,
                    options=[
                        discord.SelectOption(
                            label="Change message",
                            description="Change the message for verified users."
                        ),
                        discord.SelectOption(
                            label="Disable",
                            description="No join message for verified users."),
                    ])
            ],
            "choices": ("Change message", "Disable")
        }]))["option"][0]

        if parsed_args_1 == "Change message":
            parsed_args_2 = await CommandArgs.prompt([{
                "prompt":
                "What would you like the text of the Verified Join Message to be? You may use "
                f"these templates: ```{SERVER_VERIFIED_TEMPLATES}```",
                "name":
                "text",
                "max":
                1500,
                "formatting":
                False
            }, {
                "prompt":
                "Which **channel** would you like the join messages to be posted in?",
                "name": "channel",
                "type": "channel"
            }, {
                "prompt":
                "Let's customize the join message!",
                "name":
                "features",
                "type":
                "choice",
                "components": [
                    discord.ui.Select(
                        max_values=4,
                        options=[
                            discord.SelectOption(
                                label="Ping people",
                                description="The embed will ping people."),
                            discord.SelectOption(
                                label="Include Roblox avatar",
                                description=
                                "The embed will show the user's Roblox avatar."
                            ),
                            discord.SelectOption(
                                label="Include Roblox age",
                                description=
                                "The embed will show the user's Roblox age."),
                            discord.SelectOption(
                                label="Include Roblox username",
                                description=
                                "The embed will show the user's Roblox username."
                            ),
                            discord.SelectOption(
                                label="None of the above",
                                description="There will be no embed."),
                        ])
                ],
                "choices":
                ("Include Roblox avatar", "Ping people", "Include Roblox age",
                 "Include Roblox username", "None of the above")
            }],
                                                     last=True)

            channel = parsed_args_2["channel"]
            text = parsed_args_2["text"]
            features = parsed_args_2["features"]
            includes = {}

            if "None of the above" not in features:
                for feature in features:
                    if feature == "Ping people":
                        includes["ping"] = True
                    elif feature == "Include Roblox avatar":
                        includes["robloxAvatar"] = True
                    elif feature == "Include Roblox age":
                        includes["robloxAge"] = True
                    elif feature == "Include Roblox username":
                        includes["robloxUsername"] = True

            join_channel["verified"] = {
                "channel": str(channel.id),
                "message": text,
                "includes": includes
            }
            guild_data["joinChannel"] = join_channel

            await set_guild_value(guild, "joinChannel", join_channel)

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

        elif parsed_args_1 == "Disable":
            join_channel.pop("verified", None)
            guild_data["joinChannel"] = join_channel

            await set_guild_value(guild, "joinChannel", join_channel)

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

        change_text = f"**{'changed' if parsed_args_1 == 'Change message' else 'disabled'}**"

        await post_event(
            guild, guild_data, "configuration",
            f"{author.mention} ({author.id}) has {change_text} the `joinChannel` option for `verified` members.",
            BROWN_COLOR)

        raise Message(f"Successfully {change_text} your join message.",
                      type="success")