Exemplo n.º 1
0
	def _getStatusEmbed(self, servicesInfo):
		embed = discord.Embed(title="Server Statuses")

		successCount = 0
		totalCount = 9

		for service in servicesInfo:
			embed.add_field(name=service["name"], value=upperFirst(service["statusClass"]))
			if service["statusClass"] == "good" or service["statusClass"] == "success":
				successCount += 1

		failCount = totalCount - successCount

		# Switch between green and red depending on number of failed services
		redPercent = (failCount / totalCount) * 255
		greenPercent = (successCount / totalCount) * 255

		embed.colour = Colour.from_rgb(int(redPercent), int(greenPercent), 0)

		if failCount > 0:
			string = "are {0} services".format(failCount)
			if failCount == 1:
				string = "is 1 service"
			embed.add_field(name="Overall Status", value="There may be some latency issues because there {0} not operating at full capacity.".format(string))
		else:
			embed.add_field(name="Overall Status", value="All services running at full capacity.")

		embed.timestamp = dt.utcnow()
		embed.set_footer(text="SteamAPI from http://steamstat.us/ .")
		return embed
Exemplo n.º 2
0
    async def add(self, ctx, *, role: CustomRoleConverter):
        """
        Adds a role to the list that can be assigned
        """
        # Call the universal setup command to pull the roles from the DB
        role_me, role_me_lvl, role_me_roles, roles = await self.setup_role_me(ctx)
        if role_me == "perms":
            return

        role_me_roles = self.bot.database.get(ctx.guild.id, self.guild_storage.columns.role_me_roles)

        if not isinstance(role, discord.Role):
            await ctx.send("Could not find role! Creating blank role now :crayon: ")
            role = await ctx.guild.create_role(name=role,
                                               colour=Colour.orange(),
                                               mentionable=True,
                                               reason="Role automagically created by GAF Bot for the role list")
        if role.position >= ctx.author.top_role.position:
            await ctx.send("Unable to add role due to Hierarchy")
        else:
            role_me_roles.append(role.id)
            self.bot.database.set(ctx.guild.id, self.guild_storage.columns.role_me_roles, role_me_roles)
            await ctx.send("`Added {} to the role list`".format(role.name))
Exemplo n.º 3
0
class TypeProps():
    """Represents the properties of how a type should be represented (e.g. emoji, name, colour)."""
    def __init__(self, emoji: str, title: str, colour: Colour, **kwargs):
        self.emoji = emoji
        self.title = title
        self.colour = colour

        self.show_history = False
        self.show_in_history = False
        self.show_context = False
        for key, value in kwargs.items():
            setattr(self, key, value)


colour_ranked = Colour.from_rgb(255, 200, 90)
colour_qualified = Colour.from_rgb(255, 75, 100)
colour_nominated = Colour.from_rgb(50, 150, 255)
colour_discussion = Colour.from_rgb(65, 65, 65)
colour_resolve = Colour.from_rgb(100, 200, 100)
colour_reopen = Colour.from_rgb(255, 160, 70)
colour_news = Colour.from_rgb(255, 160, 200)
colour_added = Colour.from_rgb(130, 235, 125)
colour_removed = Colour.from_rgb(200, 160, 230)

type_props = {
    types.RANK:
    TypeProps(":sparkling_heart:", "Ranked", colour_ranked, show_history=True),
    types.LOVE:
    TypeProps(":gift_heart:", "Loved", colour_ranked, show_history=True),
    types.QUALIFY:
async def horizon_error_msg(destination, error):
    horizon_err = Embed(title=f':exclamation: Horizon API error :exclamation:',
                        colour=Colour.red())
    horizon_err.add_field(name=f'Error Details', value=f'{error}')
    await destination.send(embed=horizon_err)
Exemplo n.º 5
0
    async def superstarify(self,
                           ctx: Context,
                           member: Member,
                           duration: str,
                           *,
                           forced_nick: str = None):
        """
        This command will force a random superstar name (like Taylor Swift) to be the user's
        nickname for a specified duration. If a forced_nick is provided, it will use that instead.

        :param ctx: Discord message context
        :param ta:
        If provided, this function shows data for that specific tag.
        If not provided, this function shows the caller a list of all tags.
        """

        log.debug(
            f"Attempting to superstarify {member.display_name} for {duration}. "
            f"forced_nick is set to {forced_nick}.")

        embed = Embed()
        embed.colour = Colour.blurple()

        params = {"user_id": str(member.id), "duration": duration}

        if forced_nick:
            params["forced_nick"] = forced_nick

        response = await self.bot.http_session.post(URLs.site_superstarify_api,
                                                    headers=self.headers,
                                                    json=params)

        response = await response.json()

        if "error_message" in response:
            log.warning(
                "Encountered the following error when trying to superstarify the user:\n"
                f"{response.get('error_message')}")
            embed.colour = Colour.red()
            embed.title = random.choice(NEGATIVE_REPLIES)
            embed.description = response.get("error_message")
            return await ctx.send(embed=embed)

        else:
            forced_nick = response.get('forced_nick')
            end_time = response.get("end_timestamp")
            image_url = response.get("image_url")
            old_nick = member.display_name

            embed.title = "Congratulations!"
            embed.description = (
                f"Your previous nickname, **{old_nick}**, was so bad that we have decided to change it. "
                f"Your new nickname will be **{forced_nick}**.\n\n"
                f"You will be unable to change your nickname until \n**{end_time}**.\n\n"
                "If you're confused by this, please read our "
                f"[official nickname policy]({NICKNAME_POLICY_URL}).")
            embed.set_image(url=image_url)

            # Log to the mod_log channel
            log.trace(
                "Logging to the #mod-log channel. This could fail because of channel permissions."
            )
            mod_log_message = (
                f"**{member.name}#{member.discriminator}** (`{member.id}`)\n\n"
                f"Superstarified by **{ctx.author.name}**\n"
                f"Old nickname: `{old_nick}`\n"
                f"New nickname: `{forced_nick}`\n"
                f"Superstardom ends: **{end_time}**")
            await self.modlog.send_log_message(
                icon_url=Icons.user_update,
                colour=Colour.gold(),
                title="Member Achieved Superstardom",
                text=mod_log_message,
                thumbnail=member.avatar_url_as(static_format="png"))

            await self.moderation.notify_infraction(
                user=member,
                infr_type="Superstarify",
                duration=duration,
                reason=
                f"Your nickname didn't comply with our [nickname policy]({NICKNAME_POLICY_URL})."
            )

            # Change the nick and return the embed
            log.debug("Changing the users nickname and sending the embed.")
            await member.edit(nick=forced_nick)
            await ctx.send(embed=embed)
Exemplo n.º 6
0
    async def on_message_edit(self, msg_before: discord.Message,
                              msg_after: discord.Message) -> None:
        """Log message edit event to message change log."""
        if (not msg_before.guild or msg_before.guild.id != GuildConstant.id
                or msg_before.channel.id in GuildConstant.modlog_blacklist
                or msg_before.author.bot):
            return

        self._cached_edits.append(msg_before.id)

        if msg_before.content == msg_after.content:
            return

        author = msg_before.author
        author_str = escape_markdown(str(author))

        channel = msg_before.channel
        channel_name = f"{channel.category}/#{channel.name}" if channel.category else f"#{channel.name}"

        # Getting the difference per words and group them by type - add, remove, same
        # Note that this is intended grouping without sorting
        diff = difflib.ndiff(msg_before.clean_content.split(),
                             msg_after.clean_content.split())
        diff_groups = tuple(
            (diff_type, tuple(s[2:] for s in diff_words))
            for diff_type, diff_words in itertools.groupby(diff,
                                                           key=lambda s: s[0]))

        content_before: t.List[str] = []
        content_after: t.List[str] = []

        for index, (diff_type, words) in enumerate(diff_groups):
            sub = ' '.join(words)
            if diff_type == '-':
                content_before.append(f"[{sub}](http://o.hi)")
            elif diff_type == '+':
                content_after.append(f"[{sub}](http://o.hi)")
            elif diff_type == ' ':
                if len(words) > 2:
                    sub = (
                        f"{words[0] if index > 0 else ''}"
                        " ... "
                        f"{words[-1] if index < len(diff_groups) - 1 else ''}")
                content_before.append(sub)
                content_after.append(sub)

        response = (f"**Author:** {author_str} (`{author.id}`)\n"
                    f"**Channel:** {channel_name} (`{channel.id}`)\n"
                    f"**Message ID:** `{msg_before.id}`\n"
                    "\n"
                    f"**Before**:\n{' '.join(content_before)}\n"
                    f"**After**:\n{' '.join(content_after)}\n"
                    "\n"
                    f"[Jump to message]({msg_after.jump_url})")

        if msg_before.edited_at:
            # Message was previously edited, to assist with self-bot detection, use the edited_at
            # datetime as the baseline and create a human-readable delta between this edit event
            # and the last time the message was edited
            timestamp = msg_before.edited_at
            delta = humanize_delta(
                relativedelta(msg_after.edited_at, msg_before.edited_at))
            footer = f"Last edited {delta} ago"
        else:
            # Message was not previously edited, use the created_at datetime as the baseline, no
            # delta calculation needed
            timestamp = msg_before.created_at
            footer = None

        await self.send_log_message(Icons.message_edit,
                                    Colour.blurple(),
                                    "Message edited",
                                    response,
                                    channel_id=Channels.message_log,
                                    timestamp_override=timestamp,
                                    footer=footer)
Exemplo n.º 7
0
def get_default_embed(description):
    return Embed.from_dict({
        'description': description,
        'color': Colour.blue().value,
    })
Exemplo n.º 8
0
    async def readme(self,
                     ctx: Context,
                     operand: str = "",
                     channel_id: str = "",
                     msg_send_interval: int = 0):
        """
        Allows generating, sending and manipulation of JSON file containing the info needed
        to create and send the embeds for the #readme channel. Only ROOT_ROLE_ID users have
        the permissions need to use this command.
        """

        operand = operand.lower()

        # The supplied operand is incorrect.
        if not (operand in README_SEND_ALIASES + README_RECV_ALIASES):
            incorrect_operand_embed = Embed(
                colour=0x673ab7,
                description=":shrug: **Invalid readme operand supplied.**")
            await ctx.message.delete()
            await ctx.send(embed=incorrect_operand_embed)

        # User missed out the channel_id for certain commands.
        elif (channel_id == "" and operand in README_SEND_ALIASES):
            misssing_channel_embed = Embed(
                colour=0xff5722,
                description=
                ":facepalm: **Whoops, you missed out the channel ID! Try again.**"
            )
            await ctx.message.delete()
            await ctx.send(embed=misssing_channel_embed)

        # Process the request.
        else:
            # Let's create a series of #readme-capable embeds. If something is uploaded,
            # It will attempt to use that file for the readme, if omitted, it will use
            # the default JSONifed readme file and send that into the channel instead.
            if operand in README_SEND_ALIASES:
                try:
                    # Much pain was had fixing this. Please, get some help and install mypy type checking.
                    channel_id: int = int(channel_id[2:-1] if channel_id[0] ==
                                          "<" else channel_id)

                    usr_confirmation_embed = Embed(
                        colour=0x4caf50,
                        description=
                        ":white_check_mark: **Creating readme using uploaded config file.**"
                    )

                    # The user has uploaded a config.
                    if ctx.message.attachments != []:
                        json_file_location = [
                            _.url for _ in ctx.message.attachments
                        ][0]

                        # GETs the attachment data.
                        async with ClientSession() as session:
                            async with session.get(
                                    json_file_location) as response:
                                if response.status == 200:
                                    resp_text = await response.text()

                        json_config = load(StringIO(resp_text))
                        await ctx.send(embed=usr_confirmation_embed)

                    # No config uploaded, just use default config file.
                    else:
                        with open("cdbot/data/readme.json",
                                  "rb") as default_json:
                            json_config = load(default_json)

                        usr_confirmation_embed.description = (
                            ":ballot_box_with_check: "
                            "**Creating readme using default config file.**")
                        await ctx.send(embed=usr_confirmation_embed)

                    await ctx.message.delete()

                    for section in json_config:
                        # Initialise our message and embed variables each loop.
                        # This is to prevent leftover data from being re-sent.
                        msg_content, current_embed = None, None

                        # The part which handles general messages.
                        if "content" in json_config[section]:
                            msg_content = json_config[section]["content"]

                        # We have an embed. Call in the Seahawks.
                        if "embed" in json_config[section]:
                            current_embed = Embed()
                            msg_embed = json_config[section]["embed"]
                            if "title" in msg_embed:
                                current_embed.title = msg_embed["title"]
                            if "description" in msg_embed:
                                current_embed.description = msg_embed[
                                    "description"]
                            if "color" in msg_embed:
                                current_embed.colour = Colour(
                                    int(msg_embed["color"], 16))

                            # Parse the fields, if there are any.
                            if "fields" in msg_embed:
                                for current_field in msg_embed["fields"]:
                                    # Add the fields to the current embed.
                                    current_embed.add_field(
                                        name=current_field["name"],
                                        value=current_field["value"])

                        # Send the message.
                        requested_channel = self.bot.get_channel(channel_id)

                        if (msg_content is not None and current_embed is None):
                            await requested_channel.send(content=msg_content)
                        elif (current_embed is not None
                              and msg_content is None):
                            await requested_channel.send(embed=current_embed)
                        else:
                            await requested_channel.send(content=msg_content,
                                                         embed=current_embed)

                        # User has requested a delay between each message being sent.
                        if (0 < msg_send_interval < 901):
                            await sleep(msg_send_interval)

                    # Send the trailing embed message constant.
                    await requested_channel.send(content=END_README_MESSAGE)

                except (Exception):
                    parse_fail_embed = Embed(
                        colour=0x673ab7,
                        description=
                        ":x: **Error parsing JSON file, please ensure its valid!**"
                    )
                    await ctx.message.delete()
                    await ctx.send(embed=parse_fail_embed)

            # Pull the readme JSON constant files and slide it into the user's DMs.
            elif operand in README_RECV_ALIASES:

                # Slide it to the user's DMs.
                requesting_user = await self.bot.fetch_user(
                    ctx.message.author.id)

                await requesting_user.send(
                    content="Hey, here's your config file!",
                    file=File(fp="cdbot/data/readme.json",
                              filename='readme.json'))

                await ctx.message.delete()
                await ctx.send(embed=Embed(
                    colour=0x009688,
                    description=":airplane: **Flying in, check your DMs!**"))
Exemplo n.º 9
0
    async def ledger(self, ctx, ledger_number: int):
        try:
            data = self.hor_ledgers.ledger(sequence=ledger_number).call()
            if data:
                operations_count = len(
                    requests.get(
                        f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/operations'
                    ).json()['_embedded']["records"])
                effects_count = len(
                    requests.get(
                        f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/effects'
                    ).json()['_embedded']["records"])
                payments_count = len(
                    requests.get(
                        f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/payments'
                    ).json()['_embedded']["records"])
                transactions_count = len(
                    requests.get(
                        f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/transactions'
                    ).json()['_embedded']["records"])

                ledger_info = Embed(
                    title=
                    f':ledger: Ledger :id: {ledger_number} Information :ledger:',
                    description=
                    'Bellow is represent information for requested ledger.',
                    colour=Colour.lighter_gray())
                ledger_info.add_field(
                    name=':white_circle: Paging Token :white_circle: ',
                    value=f'`{data["paging_token"]}`',
                    inline=False)
                ledger_info.add_field(name=':timer: Closing Time :timer: ',
                                      value=f'{data["closed_at"]}')
                ledger_info.add_field(name=':hash: Ledger Hash :hash:',
                                      value=f'`{data["hash"]}`',
                                      inline=False)
                ledger_info.add_field(
                    name=':abacus: Transaction Count :abacus: ',
                    value=f'`{data["successful_transaction_count"]}`',
                    inline=False)
                ledger_info.add_field(
                    name=':wrench: Operations Count :wrench: ',
                    value=f'`{data["operation_count"]}`',
                    inline=False)
                ledger_info.add_field(
                    name=':x: Failed Transactions :x: ',
                    value=f'`{data["failed_transaction_count"]}`',
                    inline=False)
                ledger_info.add_field(
                    name=':moneybag: Total Existing XLM :moneybag: ',
                    value=f'`{data["total_coins"]} XLM`',
                    inline=False)
                ledger_info.add_field(
                    name=':money_mouth: Base Fee :money_mouth: ',
                    value=
                    f'`{format(round(data["base_fee_in_stroops"] / 10000000, 7), ".7f")} XLM`',
                    inline=False)
                ledger_info.add_field(name=':bath: Fee Pool :bath: ',
                                      value=f'`{data["fee_pool"]} XLM`',
                                      inline=False)
                ledger_info.add_field(
                    name=':arrow_forward: Protocol Version :arrow_forward: ',
                    value=f'`{data["protocol_version"]}`',
                    inline=False)
                ledger_info.add_field(
                    name=f':person_running: Ledger Activity :person_running: ',
                    value=
                    f'Operations: [{operations_count}]({data["_links"]["operations"]["href"]}) \n'
                    f'Effects: [{effects_count}]({data["_links"]["effects"]["href"]})\n'
                    f'Payments: [{payments_count}]({data["_links"]["payments"]["href"]}) \n'
                    f'Transactions: [{transactions_count}]({data["_links"]["transactions"]["href"]})'
                )
                ledger_info.set_footer(
                    text='Click on number to expand details')
                await ctx.author.send(embed=ledger_info)
        except BadRequestError as e:
            extras = e.extras
            await horizon_error_msg(destination=ctx.message.author,
                                    error=extras["reason"])
Exemplo n.º 10
0
class Colours:
    white = Colour(0xFFFFFF)
    blurple = Colour(0x7289DA)
    gold = Colour(0xE4E415)
    diamond = Colour(0xECF5FF)
Exemplo n.º 11
0
    async def on_message(self,message):
        if not message.author.bot:
            is_help = False
            ID_bot_mention = '<@!613269904963141643>'
            ID_bot_mention_without_exclamation_mark = '<@613269904963141643>'
            role_bot = '<@&698575036310618222>'
            was_already = False

            if ID_bot_mention or ID_bot_mention_without_exclamation_mark or role_bot in message.content:
                I = message.guild.get_member(506438836943978496) 
                if ID_bot_mention in message.content:
                    result =  select("Question",["question","answer"],f"question = '{message.content.replace(ID_bot_mention,'')}'")
                elif ID_bot_mention_without_exclamation_mark in  message.content:
                    result = select("Question",["question","answer"],f"question = '{message.content.replace(ID_bot_mention_without_exclamation_mark,'')}'")
                else:
                    result = select("Question",["question","answer"],f"question = '{message.content.replace(role_bot,'')}'")
            
                for row in result:
                    if row[0] == message.content.replace(ID_bot_mention,'') or message.content.replace(ID_bot_mention_without_exclamation_mark,'') or message.content.replace(role_bot,''):
                        was_already = True

                


            if message.content == ".rank" or message.content == ".card":
                is_help = True
            print(f"{message.author} : {message.content} channel {message.channel}")

            channel_logs = message.guild.get_channel(688373372945694725)
            em = Embed(description = f"{message.author} : `{message.content}` channel {message.channel}", colour = Colour.from_rgb(0, 0, 201))
            await channel_logs.send(embed = em)
            plus_lvl = 0
            if len(message.content) >= 5 and not is_help:
                result = select("Members",["xp","lvl"],f"id = {message.author.id}")

                for row in result:
                    if len(message.content) >= 15:
                        exp_plus = int(row[0]) + randint(10,19)

                        update("Members",["xp"],[f"{exp_plus}"],f"id = {message.author.id}")
                        lvl_up = exp_plus/(int(row[1]) * 50)

                        if int(row[1]) <= lvl_up:
                            plus_lvl = int(row[1]) + 1
                            await message.channel.send(f'Ура <@!{message.author.id}>, у тебя новый лвл. Теперь у тебя {plus_lvl} лвл. Ты можешь это проверить при помоши `.rank`.')

                            update("Members",["lvl"],[f"{plus_lvl}"],f"id = {message.author.id}")
                    else:
                        exp_plus = int(row[0]) + randint(3,7)

                        update("Members",["xp"],[f"{exp_plus}"],f"id = {message.author.id}")
                        lvl_up = exp_plus/(int(row[1]) * 50)

                        if int(row[1]) <= lvl_up:
                            plus_lvl = int(row[1]) + 1
                            await message.channel.send(f'Ура <@!{message.author.id}>, у тебя новый лвл. Теперь у тебя {plus_lvl} лвл. Ты можешь это проверить при помоши `.rank`.')

                            update("Members",["lvl"],[f"{plus_lvl}"],f"id = {message.author.id}")

                    if plus_lvl == 5:
                        mem5 = message.guild.get_member(message.author.id)
                        role5 = message.guild.get_role(643949984194101273)
                        role_del5 = message.guild.get_role(643902599661223951)
                        await mem5.add_roles(role5)
                        await mem5.remove_roles(role_del5)
                        await message.channel.send(f"Вам выдана роль `{str(role5).lower()}`")

                    if plus_lvl == 10:
                        mem6 = message.guild.get_member(message.author.id)
                        role6 = message.guild.get_role(643902599468285962)
                        role_del6 = message.guild.get_role(643949984194101273)
                        await mem6.add_roles(role6)
                        await mem6.remove_roles(role_del6)
                        await message.channel.send(f"Вам выдана роль `{str(role6).lower()}`")

                    if plus_lvl == 25:
                        mem7 = message.guild.get_member(message.author.id)
                        role7 = message.guild.get_role(680859240583266509)
                        role_del7 = message.guild.get_role(643902599468285962)
                        await mem7.add_roles(role7)
                        await mem7.remove_roles(role_del7)
                        await message.channel.send(f"Вам выдана роль `{str(role7).lower()}`")

                    if plus_lvl == 100:
                        mem8 = message.guild.get_member(message.author.id)
                        role8 = message.guild.get_role(643902598289686556)
                        role_del8 = message.guild.get_role(680859240583266509)
                        await mem8.add_roles(role8)
                        await mem8.remove_roles(role_del8)
                        await message.channel.send(f"Вам выдана роль `{str(role8).lower()}`")
            
            while True:
                try:
                    member = 0
                    members = message.guild.members
                    for i in range(len(members)):
                        if members[i].status == Status.online:
                            member += 1

                        elif members[i].status == Status.idle:
                            member += 1

                        elif members[i].status == Status.dnd:
                            member += 1

                        elif members[i].status == Status.invisible:
                            member += 1

                    in_online = message.guild.get_channel(703248000839057459)
                    await in_online.edit(name=f'Людей в сети: {member}')
                except:
                    pass
Exemplo n.º 12
0
 async def on_message_edit(self,before,after):
     if not before.author.bot:
         channel_logs = before.guild.get_channel(688373372945694725)
         await channel_logs.send(embed = Embed(description = f"{before.author} изменил сообщение `{before.content}` на `{after.content}`",colour = Colour.orange()))
Exemplo n.º 13
0
 async def on_message_delete(self,message):
     if not message.author.bot:
         print(f"{message.author} delete {message.content} channel {message.channel}")
         channel_logs = message.guild.get_channel(688373372945694725)
         await channel_logs.send(embed = Embed(description = f"{message.author} delete `{message.content}` channel {message.channel}", colour = Colour.from_rgb(207,192,0)))
Exemplo n.º 14
0
    async def _filter_message(self, msg: Message):
        """
        Whenever a message is sent or edited,
        run it through our filters to see if it
        violates any of our rules, and then respond
        accordingly.
        """

        # Should we filter this message?
        role_whitelisted = False

        if type(msg.author) is Member:  # Only Member has roles, not User.
            for role in msg.author.roles:
                if role.id in Filter.role_whitelist:
                    role_whitelisted = True

        filter_message = (
            msg.channel.id
            not in Filter.channel_whitelist  # Channel not in whitelist
            and not role_whitelisted  # Role not in whitelist
            and not msg.author.bot  # Author not a bot
        )

        # If we're running the bot locally, ignore role whitelist and only listen to #dev-test
        if DEBUG_MODE:
            filter_message = not msg.author.bot and msg.channel.id == Channels.devtest

        # If none of the above, we can start filtering.
        if filter_message:
            for filter_name, _filter in self.filters.items():

                # Is this specific filter enabled in the config?
                if _filter["enabled"]:
                    triggered = await _filter["function"](msg.content)

                    if triggered:
                        message = (
                            f"The {filter_name} {_filter['type']} was triggered "
                            f"by **{msg.author.name}#{msg.author.discriminator}** "
                            f"(`{msg.author.id}`) in <#{msg.channel.id}> with [the "
                            f"following message]({msg.jump_url}):\n\n"
                            f"{msg.content}")

                        log.debug(message)

                        # Send pretty mod log embed to mod-alerts
                        await self.mod_log.send_log_message(
                            icon_url=Icons.filtering,
                            colour=Colour(Colours.soft_red),
                            title=f"{_filter['type'].title()} triggered!",
                            text=message,
                            thumbnail=msg.author.avatar_url_as(
                                static_format="png"),
                            channel_id=Channels.mod_alerts,
                            ping_everyone=Filter.ping_everyone,
                        )

                        # If this is a filter (not a watchlist), we should delete the message.
                        if _filter["type"] == "filter":
                            await msg.delete()

                        break  # We don't want multiple filters to trigger
Exemplo n.º 15
0
    async def get_command(self, ctx: Context, tag_name=None):
        """
        Get a list of all tags or a specified tag.

        :param ctx: Discord message context
        :param tag_name:
        If provided, this function shows data for that specific tag.
        If not provided, this function shows the caller a list of all tags.
        """
        def _command_on_cooldown(tag_name) -> bool:
            """
            Check if the command is currently on cooldown.
            The cooldown duration is set in constants.py.

            This works on a per-tag, per-channel basis.
            :param tag_name: The name of the command to check.
            :return: True if the command is cooling down. Otherwise False.
            """

            now = time.time()

            cooldown_conditions = (
                tag_name and tag_name in self.tag_cooldowns
                and (now - self.tag_cooldowns[tag_name]["time"]) < TAG_COOLDOWN
                and self.tag_cooldowns[tag_name]["channel"] == ctx.channel.id)

            if cooldown_conditions:
                return True
            return False

        if _command_on_cooldown(tag_name):
            time_left = TAG_COOLDOWN - (time.time() -
                                        self.tag_cooldowns[tag_name]["time"])
            print(
                f"That command is currently on cooldown. Try again in {time_left:.1f} seconds."
            )
            return

        embed = Embed()
        tags = []

        tag_data = await self.get_tag_data(tag_name)

        # If we found something, prepare that data
        if tag_data:
            embed.colour = Colour.blurple()

            if tag_name:
                embed.title = tag_name
                self.tag_cooldowns[tag_name] = {
                    "time": time.time(),
                    "channel": ctx.channel.id
                }

            else:
                embed.title = "**Current tags**"

            if isinstance(tag_data, list):
                tags = [f"**»**   {tag['tag_name']}" for tag in tag_data]
                tags = sorted(tags)

            else:
                embed.description = tag_data['tag_content']

        # If not, prepare an error message.
        else:
            embed.colour = Colour.red()
            embed.description = "**There are no tags in the database!**"

            if isinstance(tag_data, dict):
                embed.description = f"Unknown tag: **{tag_name}**"

            if tag_name:
                embed.set_footer(
                    text="To show a list of all tags, use bot.tags.get().")
                embed.title = "Tag not found"

        # Paginate if this is a list of all tags
        if tags:
            return await LinePaginator.paginate(
                (lines for lines in tags),
                ctx,
                embed,
                footer_text="To show a tag, type bot.tags.get <tagname>.",
                empty=False,
                max_lines=15)

        return await ctx.send(embed=embed)
Exemplo n.º 16
0
    async def list_language(self, ctx, language: str=''):
        """
        Displays TTS narrator voices filtered by language.

        parameters:
            ctx  [Context]: context object representing command invocation
            language [str] (default=''): language to filter by
        """
        # Check if language was provided
        if not language:
            prefix = self.prefixes[ctx.guild]

            # Create a string of all available languages
            languages = "`, `".join(sorted(supported_languages.keys()))
            embed = Embed(
                title=":book: Voice Directory - Language",
                description=(f":information_source: **Use** `{prefix}list "
                              "language [Language]` **to display available "
                              "voices**"),
                colour=Colour.blue())
            embed.add_field(
                name="**Available Languages Options:**",
                value=f"`{languages}`")

        # Ensure that language is supported
        elif await language_is_valid(language):
            language = language.lower()
            lang_codes = supported_languages[language]

            field_index = 0
            page_number = 1

            # Generate embed page
            embed = Embed(
                title=( ":book: Voice Directory - Language - "
                       f"{language.capitalize()}"),
                colour=Colour.blue())
            embed.set_footer(text=f"Page #{page_number}")

            for voice_info in self._voice_filter('lang_code', *lang_codes):
                # Check if the number of fields exceeds embed page limit
                if (field_index >= self.MAX_EMBED_FIELDS):
                    field_index = 0
                    page_number += 1

                    # Send old embed page
                    await ctx.send(embed=embed)

                    # Generate new embed page
                    embed = Embed(
                        title=( ":book: Voice Directory - Language - "
                               f"{language.capitalize()}"),
                        colour=Colour.blue())
                    embed.set_footer(text=f"Page #{page_number}")

                # Add voice to embed
                embed.add_field(
                    name=f"{voice_info[0]}",
                    value=f"Region: {voice_info[1]}\nGender: {voice_info[2]}")

                field_index += 1

            # Add padding field if needed
            if field_index > 3 and field_index % 3 == 2:
                embed.add_field(name="⠀", value="⠀")

        await ctx.send(embed=embed)
Exemplo n.º 17
0
    async def quotes(self, ctx: Context) -> None:
        """Chooses between a list of quotes."""
        embed_quote = Embed(title=random.choice(lines), color=Colour.green())

        await ctx.send(embed=embed_quote)
Exemplo n.º 18
0
 async def user(self, ctx, argument=None):
     if argument is not None:
         if argument.isdigit():
             ctx.author = self.bot.get_user(int(argument))
             if ctx.author is None:
                 return await ctx.send(
                     "Sorry Senpai, I can't find anyone with that ID qwq")
         else:
             ID = argument[3:]
             ID = ID[:-1]
             ctx.author = self.bot.get_user(int(ID))
     logging_info(f'Recieved user {ctx.author.name}')
     ref = dab.collection("users").document(str(ctx.author.id)).get()
     if ref.exists is False:
         logging_info(f"User not found")
         if argument is None:
             return await ctx.send(
                 "You're not in my database, Senpai! qwq\nYou should use ``>user add`` <w<"
             )
         elif argument is not None:
             return await ctx.send("That person isn't in my database qwq")
     username = ref.get("username")
     scoresaber = ref.get("scoresaber")
     links_Message = f"[Scoresaber]({scoresaber}) "
     try:
         steam = ref.get("steam")
         links_Message = links_Message + f"| [Steam]({steam}) "
     except BaseException:
         True
     try:
         twitch = ref.get("twitch")
         links_Message = links_Message + f"| [Twitch]({twitch}) "
     except BaseException:
         True
     try:
         youtube = ref.get("youtube")
         links_Message = links_Message + f"| [Youtube]({youtube}) "
     except BaseException:
         True
     try:
         twitter = ref.get("twitter")
         links_Message = links_Message + f"| [Twitter]({twitter}) "
     except BaseException:
         True
     try:
         reddit = ref.get("reddit")
         links_Message = links_Message + f"| [Reddit]({reddit}) "
     except BaseException:
         True
     try:
         hmd = ref.get("hmd")
     except BaseException:
         hmd = None
     try:
         birthday = ref.get("birthday")
     except BaseException:
         birthday = None
     try:
         pfp = ref.get("pfp")
     except BaseException:
         pfp = None
     try:
         status = ref.get("status")
     except BaseException:
         status = None
     # try:
     #   this on for size, Mister
     try:
         colourRaw = ref.get("colour")
         colour = await commands.ColourConverter().convert(
             ctx, "0x" + colourRaw)
         embed = Embed(title=username, colour=colour)
     except BaseException:
         embed = Embed(title=username, colour=Colour.random())
     embed.add_field(name="Links", value=links_Message, inline=False)
     if hmd is not None:
         embed.add_field(name="HMD", value=hmd, inline=True)
     if birthday is not None:
         embed.add_field(name="Birthday", value=birthday, inline=True)
     if status is not None:
         embed.add_field(name="Status", value=status, inline=False)
     if pfp is not None:
         embed.set_thumbnail(url=pfp)
     else:
         embed.set_thumbnail(url=ctx.author.avatar_url)
     await ctx.reply(embed=embed)
     logging_info('Response: user embed\n----------')
Exemplo n.º 19
0
    def make_embeds(coins, current_prices, author, net_worth):
        """ This function is used to combine a series of coins into a
            embed (or more than one if wallet is big) """

        embeds = []
        num_fields = 0
        page = 1

        embed = Embed(
            title=f"{author}'s current Wallet" +
            "" if page == 1 else f" Page {page}",
            colour=Colour(0xFF00FF),
            type="rich",
            description=
            '**--------------------------------------------------------------------------------------------------**'
        )
        embed.set_footer(text="Pairs calculated via Binance")

        for c in coins:
            # if adding these 3 fields would exceed the allowed amount
            # make a new embed and save the old one someone where else
            first_field = True
            if num_fields + 5 > Constants.FIELD_LIMIT.value:
                embeds.append(embed.copy())
                page += 1
                num_fields = 0

                embed = Embed(
                    title=f"{author}'s current Wallet" +
                    "" if page == 1 else f" Page {page}",
                    colour=Colour(0xFF00FF),
                    type="rich",
                    description=
                    '**--------------------------------------------------------------------------------------------------**'
                )
                embed.set_footer(text="Pairs calculated via Binance")

            num_fields += 4
            embed.add_field(
                name=f'Coin/Pair: {c}',
                value=
                f"**Current Price**: {'$' + f'{current_prices[c][0]:,}' if current_prices[c][0] is not None else 'Unknown'} **Wallet Value**: ${current_prices[c][1]:,} USDT",
                inline=False)

            for row in coins[c]:
                price, quantity, date = row
                embed.add_field(
                    name="Buy Price" if first_field else Constants.EMPTY.value,
                    value=price,
                    inline=True)
                embed.add_field(
                    name="Quantity" if first_field else Constants.EMPTY.value,
                    value=quantity,
                    inline=True)
                embed.add_field(name="Saved at (UTC Time)"
                                if first_field else Constants.EMPTY.value,
                                value=date,
                                inline=True)
                embed.add_field(name=Constants.EMPTY.value,
                                value=Constants.EMPTY.value,
                                inline=False)

                first_field = False

        # if this statement is true, then we did not save the last embed
        if num_fields != 0:
            embeds.append(embed)

        # Adding the worth up for each price in the footer of the last embed
        embeds[-1].set_footer(
            text=f"Net worth of known coins is ${net_worth:,} USDT")
        return embeds
Exemplo n.º 20
0
Arquivo: reddit.py Projeto: vemel/bot
    async def poll_new_posts(self) -> None:
        """Periodically search for new subreddit posts."""
        while True:
            await asyncio.sleep(RedditConfig.request_delay)

            for subreddit in RedditConfig.subreddits:
                # Make a HEAD request to the subreddit
                head_response = await self.bot.http_session.head(
                    url=f"{self.URL}/{subreddit}/new.rss",
                    headers=self.HEADERS)

                content_length = head_response.headers["content-length"]

                # If the content is the same size as before, assume there's no new posts.
                if content_length == self.prev_lengths.get(subreddit, None):
                    continue

                self.prev_lengths[subreddit] = content_length

                # Now we can actually fetch the new data
                posts = await self.fetch_posts(f"{subreddit}/new")
                new_posts = []

                # Only show new posts if we've checked before.
                if subreddit in self.last_ids:
                    for post in posts:
                        data = post["data"]

                        # Convert the ID to an integer for easy comparison.
                        int_id = int(data["id"], 36)

                        # If we've already seen this post, finish checking
                        if int_id <= self.last_ids[subreddit]:
                            break

                        embed_data = {
                            "title":
                            textwrap.shorten(data["title"],
                                             width=64,
                                             placeholder="..."),
                            "text":
                            textwrap.shorten(data["selftext"],
                                             width=128,
                                             placeholder="..."),
                            "url":
                            self.URL + data["permalink"],
                            "author":
                            data["author"]
                        }

                        new_posts.append(embed_data)

                self.last_ids[subreddit] = int(posts[0]["data"]["id"], 36)

                # Send all of the new posts as spicy embeds
                for data in new_posts:
                    embed = Embed()

                    embed.title = data["title"]
                    embed.url = data["url"]
                    embed.description = data["text"]
                    embed.set_footer(
                        text=f"Posted by u/{data['author']} in {subreddit}")
                    embed.colour = Colour.blurple()

                    await self.reddit_channel.send(embed=embed)

                log.trace(
                    f"Sent {len(new_posts)} new {subreddit} posts to channel {self.reddit_channel.id}."
                )
Exemplo n.º 21
0
    async def warn(self, ctx, member: Member, *, reason: str = ""):
        """
        Warn members. (Staff Only)
        A user ID can be used instead of mentionning the user.
        - First warn : nothing happens, a simple warning
        - Second warn : muted until an the admin who issued the warning decides to unmute the user.
        - Third warn : kicked
        - Fourth warn : kicked
        - Fifth warn : banned
        """
        author = ctx.message.author

        if member == ctx.message.author:
            await ctx.send("You cannot warn yourself!")
            return
        if self.bot.staff_role in member.roles and self.bot.owner_role not in author.roles:
            await ctx.send("You cannot warn other staff members!")
            return
        elif self.bot.owner_role in member.roles:
            await ctx.send("💢 I don't have the permission to do that!")
            return
        elif ctx.me is member:
            await ctx.send("I should not warn myself!")
            return

        try:
            with open("database/warns.json", "r") as config:
                js = load(config)
        except FileNotFoundError:
            with open("database/warns.json", "w") as config:
                config.write('{}')
                js = {}

        userid = str(member.id)
        if userid not in js:
            amount_of_warns = 1
            js[userid] = {"warns": []}
        else:
            amount_of_warns = len(js[userid]["warns"]) + 1

        member_name = "{}#{}".format(member.name, member.discriminator)
        timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime())
        author_name = "{}#{}".format(author.name, author.discriminator)

        js[userid]["amount"] = amount_of_warns
        js[userid]["warns"].append({
            "name": member_name,
            "timestamp": timestamp,
            "reason": reason,
            "author": author_name,
            "author_id": author.id,
        })
        await ctx.send("🚩 I've warned {}. The user now has {} warns."
                       "".format(member, amount_of_warns))
        if reason == "":
            await self.dm(member,
                          "You have been warned in {}.".format(ctx.guild.name))
        else:
            await self.dm(
                member,
                "You have been warned in {} for the following reason :\n{}\n"
                "".format(ctx.guild.name, reason))
        emb = Embed(title="Member Warned", colour=Colour.orange())
        emb.add_field(name="Member:", value=member, inline=True)
        emb.add_field(name="Warning Number:",
                      value=amount_of_warns,
                      inline=True)
        emb.add_field(name="Mod:", value=ctx.message.author, inline=True)
        if reason == "":
            reason = "No reason specified."
        emb.add_field(name="Reason:", value=reason, inline=True)
        logchannel = self.bot.logs_channel
        await logchannel.send("", embed=emb)

        if amount_of_warns == 1:
            await self.dm(
                member, "This is your first warning. "
                "The next warning will automatically mute you.")
        elif amount_of_warns == 2:
            await self.dm(
                member,
                "This is your second warning, so you've been muted. You will be unmuted "
                "whenever the admin who warned you decides to unmute you.\nYou will be "
                "DM'ed when a mod unmutes you.\n**Do not ask mods to unmute you, as "
                "doing so might extend the duration of the mute**")
            await self.dm(
                member,
                "Your next warn will result in being kicked from the server.")
            await member.add_roles(self.bot.muted_role)
        elif amount_of_warns == 3:
            await self.dm(
                member,
                "This is your third warning, so you have been kicked. Please "
                "note that **the next warn will result in another kick!**")
            await member.kick(reason="Third warn")
        elif amount_of_warns == 4:
            await self.dm(
                member,
                "You have been kicked from the server. This is your fourth and "
                "final warning. **__The next warning will result in an automatic"
                " permanent ban.__**")
            await member.kick(reason="Fourth warn")
        elif amount_of_warns >= 5:
            await self.dm(
                member,
                "You have reached your fifth warning. You are now permanently "
                "banned from this server.")
            await member.ban(delete_message_days=0, reason="Fifth warn.")

        with open("database/warns.json", "w") as f:
            dump(js, f, sort_keys=True, indent=4, separators=(',', ': '))
Exemplo n.º 22
0
    async def on_guild_channel_update(self, before: GUILD_CHANNEL,
                                      after: GuildChannel) -> None:
        """Log channel update event to mod log."""
        if before.guild.id != GuildConstant.id:
            return

        if before.id in self._ignored[Event.guild_channel_update]:
            self._ignored[Event.guild_channel_update].remove(before.id)
            return

        # Two channel updates are sent for a single edit: 1 for topic and 1 for category change.
        # TODO: remove once support is added for ignoring multiple occurrences for the same channel.
        help_categories = (Categories.help_available, Categories.help_dormant,
                           Categories.help_in_use)
        if after.category and after.category.id in help_categories:
            return

        diff = DeepDiff(before, after)
        changes = []
        done = []

        diff_values = diff.get("values_changed", {})
        diff_values.update(diff.get("type_changes", {}))

        for key, value in diff_values.items():
            if not key:  # Not sure why, but it happens
                continue

            key = key[5:]  # Remove "root." prefix

            if "[" in key:
                key = key.split("[", 1)[0]

            if "." in key:
                key = key.split(".", 1)[0]

            if key in done or key in CHANNEL_CHANGES_SUPPRESSED:
                continue

            if key in CHANNEL_CHANGES_UNSUPPORTED:
                changes.append(f"**{key.title()}** updated")
            else:
                new = value["new_value"]
                old = value["old_value"]

                # Discord does not treat consecutive backticks ("``") as an empty inline code block, so the markdown
                # formatting is broken when `new` and/or `old` are empty values. "None" is used for these cases so
                # formatting is preserved.
                changes.append(
                    f"**{key.title()}:** `{old or 'None'}` **→** `{new or 'None'}`"
                )

            done.append(key)

        if not changes:
            return

        message = ""

        for item in sorted(changes):
            message += f"{Emojis.bullet} {item}\n"

        if after.category:
            message = f"**{after.category}/#{after.name} (`{after.id}`)**\n{message}"
        else:
            message = f"**#{after.name}** (`{after.id}`)\n{message}"

        await self.send_log_message(Icons.hash_blurple, Colour.blurple(),
                                    "Channel updated", message)
Exemplo n.º 23
0
    async def clean_cancel(self, ctx: Context) -> None:
        """If there is an ongoing cleaning process, attempt to immediately cancel it."""
        self.cleaning = False

        embed = Embed(color=Colour.blurple(), description="Clean interrupted.")
        await ctx.send(embed=embed, delete_after=10)
Exemplo n.º 24
0
    async def on_voice_state_update(self, member: discord.Member,
                                    before: discord.VoiceState,
                                    after: discord.VoiceState) -> None:
        """Log member voice state changes to the voice log channel."""
        if (member.guild.id != GuildConstant.id
                or (before.channel
                    and before.channel.id in GuildConstant.modlog_blacklist)):
            return

        if member.id in self._ignored[Event.voice_state_update]:
            self._ignored[Event.voice_state_update].remove(member.id)
            return

        # Exclude all channel attributes except the name.
        diff = DeepDiff(
            before,
            after,
            exclude_paths=("root.session_id", "root.afk"),
            exclude_regex_paths=r"root\.channel\.(?!name)",
        )

        # A type change seems to always take precedent over a value change. Furthermore, it will
        # include the value change along with the type change anyway. Therefore, it's OK to
        # "overwrite" values_changed; in practice there will never even be anything to overwrite.
        diff_values = {
            **diff.get("values_changed", {}),
            **diff.get("type_changes", {})
        }

        icon = Icons.voice_state_blue
        colour = Colour.blurple()
        changes = []

        for attr, values in diff_values.items():
            if not attr:  # Not sure why, but it happens.
                continue

            old = values["old_value"]
            new = values["new_value"]

            attr = attr[5:]  # Remove "root." prefix.
            attr = VOICE_STATE_ATTRIBUTES.get(
                attr,
                attr.replace("_", " ").capitalize())

            changes.append(f"**{attr}:** `{old}` **→** `{new}`")

            # Set the embed icon and colour depending on which attribute changed.
            if any(name in attr for name in ("Channel", "deaf", "mute")):
                if new is None or new is True:
                    # Left a channel or was muted/deafened.
                    icon = Icons.voice_state_red
                    colour = Colours.soft_red
                elif old is None or old is True:
                    # Joined a channel or was unmuted/undeafened.
                    icon = Icons.voice_state_green
                    colour = Colours.soft_green

        if not changes:
            return

        member_str = escape_markdown(str(member))
        message = "\n".join(f"{Emojis.bullet} {item}"
                            for item in sorted(changes))
        message = f"**{member_str}** (`{member.id}`)\n{message}"

        await self.send_log_message(
            icon_url=icon,
            colour=colour,
            title="Voice state updated",
            text=message,
            thumbnail=member.avatar_url_as(static_format="png"),
            channel_id=Channels.voice_log)
Exemplo n.º 25
0
    async def _clean_messages(
        self,
        amount: int,
        ctx: Context,
        channels: Iterable[TextChannel],
        bots_only: bool = False,
        user: User = None,
        regex: Optional[str] = None,
        until_message: Optional[Message] = None,
    ) -> None:
        """A helper function that does the actual message cleaning."""
        def predicate_bots_only(message: Message) -> bool:
            """Return True if the message was sent by a bot."""
            return message.author.bot

        def predicate_specific_user(message: Message) -> bool:
            """Return True if the message was sent by the user provided in the _clean_messages call."""
            return message.author == user

        def predicate_regex(message: Message) -> bool:
            """Check if the regex provided in _clean_messages matches the message content or any embed attributes."""
            content = [message.content]

            # Add the content for all embed attributes
            for embed in message.embeds:
                content.append(embed.title)
                content.append(embed.description)
                content.append(embed.footer.text)
                content.append(embed.author.name)
                for field in embed.fields:
                    content.append(field.name)
                    content.append(field.value)

            # Get rid of empty attributes and turn it into a string
            content = [attr for attr in content if attr]
            content = "\n".join(content)

            # Now let's see if there's a regex match
            if not content:
                return False
            else:
                return bool(re.search(regex.lower(), content.lower()))

        # Is this an acceptable amount of messages to clean?
        if amount > CleanMessages.message_limit:
            embed = Embed(
                color=Colour(Colours.soft_red),
                title=random.choice(NEGATIVE_REPLIES),
                description=
                f"You cannot clean more than {CleanMessages.message_limit} messages."
            )
            await ctx.send(embed=embed)
            return

        # Are we already performing a clean?
        if self.cleaning:
            embed = Embed(
                color=Colour(Colours.soft_red),
                title=random.choice(NEGATIVE_REPLIES),
                description=
                "Please wait for the currently ongoing clean operation to complete."
            )
            await ctx.send(embed=embed)
            return

        # Set up the correct predicate
        if bots_only:
            predicate = predicate_bots_only  # Delete messages from bots
        elif user:
            predicate = predicate_specific_user  # Delete messages from specific user
        elif regex:
            predicate = predicate_regex  # Delete messages that match regex
        else:
            predicate = None  # Delete all messages

        # Default to using the invoking context's channel
        if not channels:
            channels = [ctx.channel]

        # Delete the invocation first
        self.mod_log.ignore(Event.message_delete, ctx.message.id)
        try:
            await ctx.message.delete()
        except errors.NotFound:
            # Invocation message has already been deleted
            log.info(
                "Tried to delete invocation message, but it was already deleted."
            )

        messages = []
        message_ids = []
        self.cleaning = True

        # Find the IDs of the messages to delete. IDs are needed in order to ignore mod log events.
        for channel in channels:
            async for message in channel.history(limit=amount):

                # If at any point the cancel command is invoked, we should stop.
                if not self.cleaning:
                    return

                # If we are looking for specific message.
                if until_message:

                    # we could use ID's here however in case if the message we are looking for gets deleted,
                    # we won't have a way to figure that out thus checking for datetime should be more reliable
                    if message.created_at < until_message.created_at:
                        # means we have found the message until which we were supposed to be deleting.
                        break

                    # Since we will be using `delete_messages` method of a TextChannel and we need message objects to
                    # use it as well as to send logs we will start appending messages here instead adding them from
                    # purge.
                    messages.append(message)

                # If the message passes predicate, let's save it.
                if predicate is None or predicate(message):
                    message_ids.append(message.id)

        self.cleaning = False

        # Now let's delete the actual messages with purge.
        self.mod_log.ignore(Event.message_delete, *message_ids)
        for channel in channels:
            if until_message:
                for i in range(0, len(messages), 100):
                    # while purge automatically handles the amount of messages
                    # delete_messages only allows for up to 100 messages at once
                    # thus we need to paginate the amount to always be <= 100
                    await channel.delete_messages(messages[i:i + 100])
            else:
                messages += await channel.purge(limit=amount, check=predicate)

        # Reverse the list to restore chronological order
        if messages:
            messages = reversed(messages)
            log_url = await self.mod_log.upload_log(messages, ctx.author.id)
        else:
            # Can't build an embed, nothing to clean!
            embed = Embed(color=Colour(Colours.soft_red),
                          description="No matching messages could be found.")
            await ctx.send(embed=embed, delete_after=10)
            return

        # Build the embed and send it
        target_channels = ", ".join(channel.mention for channel in channels)

        message = (
            f"**{len(message_ids)}** messages deleted in {target_channels} by "
            f"{ctx.author.mention}\n\n"
            f"A log of the deleted messages can be found [here]({log_url}).")

        await self.mod_log.send_log_message(
            icon_url=Icons.message_bulk_delete,
            colour=Colour(Colours.soft_red),
            title="Bulk message delete",
            text=message,
            channel_id=Channels.mod_log,
        )
Exemplo n.º 26
0
def get_item(name):
    """Returns a dictionary containing an item's info, if no exact match was found, it returns a list of suggestions.

    The dictionary has the following keys: name, look_text, npcs_sold*, value_sell, npcs_bought*, value_buy.
        *npcs_sold and npcs_bought are list, each element is a dictionary with the keys: name, city."""

    # Reading item database
    c = tibiaDatabase.cursor()

    # Search query
    c.execute(
        "SELECT * FROM Items WHERE title LIKE ? ORDER BY LENGTH(title) ASC LIMIT 15",
        ("%" + name + "%", ))
    result = c.fetchall()
    if len(result) == 0:
        return None
    elif result[0]["title"].lower() == name.lower() or len(result) == 1:
        item = result[0]
    else:
        return [x['title'] for x in result]
    try:
        # Checking if item exists
        if item is not None:
            # Checking NPCs that buy the item
            c.execute(
                "SELECT NPCs.title, city, value "
                "FROM Items, SellItems, NPCs "
                "WHERE Items.name LIKE ? AND SellItems.itemid = Items.id AND NPCs.id = vendorid "
                "ORDER BY value DESC", (name, ))
            npcs = []
            value_sell = None
            for npc in c:
                name = npc["title"]
                city = npc["city"].title()
                if value_sell is None:
                    value_sell = npc["value"]
                elif npc["value"] != value_sell:
                    break
                # Replacing cities for special npcs and adding colors
                if name == 'Alesar' or name == 'Yaman':
                    city = 'Green Djinn\'s Fortress'
                    item["color"] = Colour.green()
                elif name == 'Nah\'Bob' or name == 'Haroun':
                    city = 'Blue Djinn\'s Fortress'
                    item["color"] = Colour.blue()
                elif name == 'Rashid':
                    city = get_rashid_city()
                    item["color"] = Colour(0xF0E916)
                elif name == 'Yasir':
                    city = 'his boat'
                elif name == 'Briasol':
                    item["color"] = Colour(0xA958C4)
                npcs.append({"name": name, "city": city})
            item['npcs_sold'] = npcs
            item['value_sell'] = value_sell

            # Checking NPCs that sell the item
            c.execute(
                "SELECT NPCs.title, city, value "
                "FROM Items, BuyItems, NPCs "
                "WHERE Items.name LIKE ? AND BuyItems.itemid = Items.id AND NPCs.id = vendorid "
                "ORDER BY value ASC", (name, ))
            npcs = []
            value_buy = None
            for npc in c:
                name = npc["title"]
                city = npc["city"].title()
                if value_buy is None:
                    value_buy = npc["value"]
                elif npc["value"] != value_buy:
                    break
                # Replacing cities for special npcs
                if name == 'Alesar' or name == 'Yaman':
                    city = 'Green Djinn\'s Fortress'
                elif name == 'Nah\'Bob' or name == 'Haroun':
                    city = 'Blue Djinn\'s Fortress'
                elif name == 'Rashid':
                    offset = get_tibia_time_zone() - get_local_timezone()
                    # Server save is at 10am, so in tibia a new day starts at that hour
                    tibia_time = datetime.now() + timedelta(hours=offset - 10)
                    city = [
                        "Svargrond", "Liberty Bay", "Port Hope", "Ankrahmun",
                        "Darashia", "Edron", "Carlin"
                    ][tibia_time.weekday()]
                elif name == 'Yasir':
                    city = 'his boat'
                npcs.append({"name": name, "city": city})
            item['npcs_bought'] = npcs
            item['value_buy'] = value_buy

            # Get creatures that drop it
            c.execute(
                "SELECT Creatures.title as name, CreatureDrops.percentage "
                "FROM CreatureDrops, Creatures "
                "WHERE CreatureDrops.creatureid = Creatures.id AND CreatureDrops.itemid = ? "
                "ORDER BY percentage DESC", (item["id"], ))
            item["dropped_by"] = c.fetchall()
            # Checking quest rewards:
            c.execute(
                "SELECT Quests.title FROM Quests, QuestRewards "
                "WHERE Quests.id = QuestRewards.questid and itemid = ?",
                (item["id"], ))
            quests = c.fetchall()
            item["quests"] = list()
            for quest in quests:
                item["quests"].append(quest["title"])
            return item
    finally:
        c.close()
    return
Exemplo n.º 27
0
    async def on_member_update(self, before: discord.Member,
                               after: discord.Member) -> None:
        """Log member update event to user log."""
        if before.guild.id != GuildConstant.id:
            return

        if before.id in self._ignored[Event.member_update]:
            self._ignored[Event.member_update].remove(before.id)
            return

        diff = DeepDiff(before, after)
        changes = []
        done = []

        diff_values = {}

        diff_values.update(diff.get("values_changed", {}))
        diff_values.update(diff.get("type_changes", {}))
        diff_values.update(diff.get("iterable_item_removed", {}))
        diff_values.update(diff.get("iterable_item_added", {}))

        diff_user = DeepDiff(before._user, after._user)

        diff_values.update(diff_user.get("values_changed", {}))
        diff_values.update(diff_user.get("type_changes", {}))
        diff_values.update(diff_user.get("iterable_item_removed", {}))
        diff_values.update(diff_user.get("iterable_item_added", {}))

        for key, value in diff_values.items():
            if not key:  # Not sure why, but it happens
                continue

            key = key[5:]  # Remove "root." prefix

            if "[" in key:
                key = key.split("[", 1)[0]

            if "." in key:
                key = key.split(".", 1)[0]

            if key in done or key in MEMBER_CHANGES_SUPPRESSED:
                continue

            if key == "_roles":
                new_roles = after.roles
                old_roles = before.roles

                for role in old_roles:
                    if role not in new_roles:
                        changes.append(
                            f"**Role removed:** {role.name} (`{role.id}`)")

                for role in new_roles:
                    if role not in old_roles:
                        changes.append(
                            f"**Role added:** {role.name} (`{role.id}`)")

            else:
                new = value.get("new_value")
                old = value.get("old_value")

                if new and old:
                    changes.append(f"**{key.title()}:** `{old}` **→** `{new}`")

            done.append(key)

        if before.name != after.name:
            changes.append(
                f"**Username:** `{before.name}` **→** `{after.name}`")

        if before.discriminator != after.discriminator:
            changes.append(
                f"**Discriminator:** `{before.discriminator}` **→** `{after.discriminator}`"
            )

        if before.display_name != after.display_name:
            changes.append(
                f"**Display name:** `{before.display_name}` **→** `{after.display_name}`"
            )

        if not changes:
            return

        message = ""

        for item in sorted(changes):
            message += f"{Emojis.bullet} {item}\n"

        message = f"**{after}** (`{after.id}`)\n{message}"

        await self.send_log_message(
            Icons.user_update,
            Colour.blurple(),
            "Member updated",
            message,
            thumbnail=after.avatar_url_as(static_format="png"),
            channel_id=Channels.user_log)
Exemplo n.º 28
0
    async def voice_verify(self, ctx: Context, *_) -> None:
        """
        Apply to be able to use voice within the Discord server.

        In order to use voice you must meet all three of the following criteria:
        - You must have over a certain number of messages within the Discord server
        - You must have accepted our rules over a certain number of days ago
        - You must not be actively banned from using our voice channels
        - You must have been active for over a certain number of 10-minute blocks
        """
        await self._delete_ping(
            ctx.author.id
        )  # If user has received a ping in voice_verification, delete the message

        try:
            data = await self.bot.api_client.get(
                f"bot/users/{ctx.author.id}/metricity_data")
        except ResponseCodeError as e:
            if e.status == 404:
                embed = discord.Embed(
                    title="Not found",
                    description=
                    ("We were unable to find user data for you. "
                     "Please try again shortly, "
                     "if this problem persists please contact the server staff through Modmail."
                     ),
                    color=Colour.red())
                log.info(
                    f"Unable to find Metricity data about {ctx.author} ({ctx.author.id})"
                )
            else:
                embed = discord.Embed(
                    title="Unexpected response",
                    description=
                    ("We encountered an error while attempting to find data for your user. "
                     "Please try again and let us know if the problem persists."
                     ),
                    color=Colour.red())
                log.warning(
                    f"Got response code {e.status} while trying to get {ctx.author.id} Metricity data."
                )
            try:
                await ctx.author.send(embed=embed)
            except discord.Forbidden:
                log.info(
                    "Could not send user DM. Sending in voice-verify channel and scheduling delete."
                )
                await ctx.send(embed=embed)

            return

        checks = {
            "joined_at":
            (ctx.author.joined_at >
             arrow.utcnow() - timedelta(days=GateConf.minimum_days_member)),
            "total_messages":
            data["total_messages"] < GateConf.minimum_messages,
            "voice_banned":
            data["voice_banned"],
            "activity_blocks":
            data["activity_blocks"] < GateConf.minimum_activity_blocks,
        }

        failed = any(checks.values())
        failed_reasons = [
            MESSAGE_FIELD_MAP[key] for key, value in checks.items()
            if value is True
        ]
        [
            self.bot.stats.incr(f"voice_gate.failed.{key}")
            for key, value in checks.items() if value is True
        ]

        if failed:
            embed = discord.Embed(
                title="Voice Gate failed",
                description=FAILED_MESSAGE.format(reasons="\n".join(
                    f'• You {reason}.' for reason in failed_reasons)),
                color=Colour.red())
            try:
                await ctx.author.send(embed=embed)
                await ctx.send(f"{ctx.author}, please check your DMs.")
            except discord.Forbidden:
                await ctx.channel.send(ctx.author.mention, embed=embed)
            return

        self.mod_log.ignore(Event.member_update, ctx.author.id)
        embed = discord.Embed(
            title="Voice gate passed",
            description=
            "You have been granted permission to use voice channels in Python Discord.",
            color=Colour.green())

        if ctx.author.voice:
            embed.description += "\n\nPlease reconnect to your voice channel to be granted your new permissions."

        try:
            await ctx.author.send(embed=embed)
            await ctx.send(f"{ctx.author}, please check your DMs.")
        except discord.Forbidden:
            await ctx.channel.send(ctx.author.mention, embed=embed)

        # wait a little bit so those who don't get DMs see the response in-channel before losing perms to see it.
        await asyncio.sleep(3)
        await ctx.author.add_roles(discord.Object(Roles.voice_verified),
                                   reason="Voice Gate passed")

        self.bot.stats.incr("voice_gate.passed")
Exemplo n.º 29
0
 async def roll(self, ctx: commands.Context, *, roll: str = 'D'):
     parts = []
     if '+' in roll or '-' in roll:
         for part in roll.split('+'):
             if not part.strip():
                 continue
             if '-' in roll:
                 for i in range(len(part.split('-'))):
                     parts_ = part.split('-')
                     if not parts_[i].strip():
                         continue
                     part_dict = {
                         'raw': parts_[i].strip().upper(),
                         'sign': '-',
                         'process': None,
                         'result': None
                     }
                     if i:
                         part_dict['sign'] = '-'
                     else:
                         part_dict['sign'] = '+'
                     parts.append(part_dict)
             else:
                 parts.append({
                     'raw': part.strip().upper(),
                     'sign': '+',
                     'process': None,
                     'result': None
                 })
     else:
         parts.append({
             'raw': roll.strip().upper(),
             'sign': '+',
             'process': None,
             'result': None
         })
     for part in parts:
         part['raw'] = part['raw'].replace(' ', '', part['raw'].count(' '))
         if 'D' in part['raw']:
             raws = part['raw'].split('D')
             try:
                 dices = int(raws[0].strip() if raws[0] else 1)
                 pips = int((raws[1].strip() if raws[1] != '%' else '100'
                             ) if raws[1] else 6)
             except ValueError:
                 await ctx.send('주사위 수와 눈을 정확한 숫자로 입력해주세요.')
                 return
             if dices <= 0:
                 await ctx.send('주사위의 수는 한 개 이상이어야 합니다.')
                 return
             if pips <= 0:
                 await ctx.send('주사위의 눈은 한 개 이상이어야 합니다.')
                 return
             throwns = []
             for i in range(dices):
                 throwns.append(randint(1, pips))
             part['process'] = str(throwns)
             part['result'] = sum(throwns) * (-1
                                              if part['sign'] == '-' else 1)
         else:
             part['process'] = part['raw']
             try:
                 part['result'] = int(
                     part['raw']) * (-1 if part['sign'] == '-' else 1)
             except ValueError:
                 await ctx.send('더하는 값을 정확한 숫자로 입력해주세요.')
                 return
     raw_description = ''
     process_description = ''
     for part in parts:
         raw_description += f'{part["sign"]} {part["raw"]} '
         process_description += f'{part["sign"]} {part["process"]} '
     description = '**' + raw_description + '**'
     description += '\n= ' + process_description
     description += '\n= ***__' + str(sum(part['result']
                                          for part in parts)) + '__***'
     embed = Embed(title=':game_die: 주사위 굴림',
                   description=description,
                   colour=Colour.blurple())
     embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url)
     embed.set_thumbnail(url=self.client.user.avatar_url)
     await ctx.send(ctx.author.mention, embed=embed)
Exemplo n.º 30
0
    async def getserver(self, ctx, serverip: str):
        """Get infos about a gameserver"""

        while serverip.find(":") == -1:
            print("No port specified using 27015\n")
            serverip += ":27015"

        serverc = serverip.split(":")
        if not serverc[0][0].isdigit():
            try:
                ip = gethostbyname_ex(serverc[0])[2][0]
            except:
                await self.bot.say("The specified domain is not valid")
                return
            servercheck = ip
            serverc = [str(ip), int(serverc[1])]
        else:
            servercheck = serverc[0]
            serverc = [str(serverc[0]), int(serverc[1])]
        serverc = tuple(serverc)

        if not self.validate_ip(str(servercheck)):
            await send_cmd_help(ctx)
            return

        try:
            server = valve.source.a2s.ServerQuerier(serverc)
            try:
                info = server.get_info(
                )  # workaround for old version ADD GIT SUPPORT 26
            except:
                info = server.info()

        except valve.source.a2s.NoResponseError:
            await self.bot.say(
                "Could not fetch Server or the Server is not on the Steam masterlist"
            )
            return
        except:
            await self.bot.say("Unkown Error has occured")
            return

        map = info.values['map']

        if map.lower().startswith("workshop"):
            link = "https://steamcommunity.com/sharedfiles/filedetails/?id={}".format(
                map.split("/")[1])
            map = "{} [(Workshop map)]({})".format(map.split("/")[2], link)

        game = info.values['folder']
        gamemode = info.values['game']

        servername = info.values['server_name'].strip()

        playernumber = str(info.values['player_count'] -
                           info.values['bot_count'])
        botnumber = str(info.values['bot_count'])
        maxplayers = str(info.values['max_players'])

        if int(info.values['vac_enabled']):
            vac = "enabled"
        else:
            vac = "disabled"
        os = str(info.values['platform'])

        em = Embed(colour=Colour.green())
        em.add_field(name="Game", value=game)
        em.add_field(name="Gamemode", value=gamemode)
        em.add_field(name="servername", value=servername, inline=False)
        em.add_field(name="IP", value=serverc[0])
        em.add_field(name="Operating System", value=os)
        em.add_field(name="VAC", value=vac)
        if botnumber != '0':
            if botnumber == "1":
                em.add_field(name="Playernumber",
                             value="{}/{}\n{} Bot".format(
                                 playernumber, maxplayers, botnumber))
            else:
                em.add_field(name="Playernumber",
                             value="{}/{}\n{} Bots".format(
                                 playernumber, maxplayers, botnumber))
        else:
            em.add_field(name="Playernumber",
                         value="{}/{}\n".format(playernumber, maxplayers))
        em.add_field(name="Map", value=map, inline=False)
        em.add_field(
            name=u"\u2063",
            value=
            "[Connect](steam://connect/{})\n(starting the game over this link may result in lag)"
            .format(serverip),
            inline=False)

        await self.bot.say(embed=em)
Exemplo n.º 31
0
async def update_status(get_embed=False):
    global first_seen, last_seen
    global server_sec1, sec1_online, sec1_motd, sec1_players, sec1_max, sec1_version
    global server_sec2, sec2_online, sec2_motd, sec2_players, sec2_max, sec2_version

    embed = Embed(
        #title="Szkolny.eu Minecraft",
        color=Colour.from_rgb(0x21, 0x96, 0xf3),
        url=HOMEPAGE_URL
    )

    embed.set_footer(text=f'Aktualizacja: {datetime.now().strftime(DATE_FORMAT)}')

    try:
        await server_status(embed)
    except Exception as e:
        await server_disconnected(embed, e)

    if SEC1_IP:
        if sec1_online:
            uptime = datetime.now() - sec1_online
            uptime = str(uptime).split('.')[0]

            embed.add_field(
                name=SEC1_NAME,
                value=f':white_check_mark: {sec1_motd}\n'
                      f'`{sec1_players}/{sec1_max} graczy, {sec1_version}, {uptime}`\n'
                      f'{SEC1_DESCRIPTION}',
                inline=False
            )
        else:
            embed.add_field(
                name=SEC1_NAME,
                value=f':x: {sec1_motd}',
                inline=False
            )

    if SEC2_IP:
        if sec2_online:
            uptime = datetime.now() - sec2_online
            uptime = str(uptime).split('.')[0]

            embed.add_field(
                name=SEC2_NAME,
                value=f':white_check_mark: {sec2_motd}\n'
                      f'`{sec2_players}/{sec2_max} graczy, {sec2_version}, {uptime}`\n'
                      f'{SEC2_DESCRIPTION}',
                inline=False
            )
        else:
            embed.add_field(
                name=SEC2_NAME,
                value=f':x: {sec2_motd}',
                inline=False
            )

    global message
    if message and not get_embed:
        await message.edit(embed=embed, content="")
    elif get_embed:
        return embed
Exemplo n.º 32
0
 async def create_blank_role(self, ctx, role):
     await ctx.guild.create_role(name=role,
                                 colour=Colour.orange(),
                                 mentionable=True,
                                 reason=f"Blank role created by GAF Bot, invoked by {ctx.author}")
     await ctx.send("Created blank role :pencil:")
Exemplo n.º 33
0
async def mc(ctx, arg):
    await ctx.message.delete()

    if arg == "status":
        return

    db = mysql.connector.connect(
        host=MYSQL_HOST,
        user=MYSQL_USER,
        passwd=MYSQL_PASSWORD
    )

    arg = arg.split()
    if len(arg) > 1:
        arg = arg[1]
    else:
        arg = ''

    # global message
    # if arg == "init" and not message:
    #     embed = await update_status(get_embed=True)
    #     message = await ctx.send(embed=embed)
    #     return

    embed = Embed(
        title="Szkolny.eu Minecraft",
        color=Colour.from_rgb(0x21, 0x96, 0xf3),
        url=HOMEPAGE_URL
    )
    embed.set_thumbnail(url=EMBED_IMAGE_URL)
    embed.description = \
        'Użycie:\n' \
        '`/mc <nickname>` - Dodaj swój nickname do whitelisty\n'  # \
    # '`/mc status` - Wyświetl status serwera\n'

    if arg and arg != 'status':
        nickname = arg
        discord_id = ctx.author.id
        discord_tag = f'{ctx.author.name}#{ctx.author.discriminator}'
        cursor = db.cursor(dictionary=True)

        embed.description = f"Dodano gracza {nickname} do whitelisty."

        cursor.execute('SELECT * FROM minecraft.whitelist WHERE name = %s OR discordId = %s', (nickname, discord_id))
        row = cursor.fetchall()
        if len(row) > 0:
            row = row[0]
            if row:
                if row['name'] == nickname and row['discordId'] != discord_id:
                    embed.description = f"Gracz {nickname} został już dodany przez `{row['discordTag']}`."
                    msg = await ctx.send(embed=embed)
                    await msg.delete(delay=5)
                    return
                if row['name'] != nickname: # and row['discordId'] == discord_id:
                    embed.description = f"Dodałeś już gracza {row['name']}, zostanie on zastąpiony graczem {nickname}."

        try:
            cursor.execute(
                'REPLACE INTO minecraft.whitelist (name, discordId, discordTag) VALUES (%s, %s, %s)',
                (nickname, discord_id, discord_tag)
            )
            db.commit()
        except mysql.connector.errors.IntegrityError:
            embed.description = f"To konto Discord ma już gracza na serwerze."

    msg = await ctx.send(embed=embed)
    await msg.delete(delay=5)