Example #1
0
    def __init__(self,
                 *args,
                 pages: list[Union[str, Embed]] = None,
                 num_pages=None,
                 original_author: User = None,
                 guild: Guild,
                 **kwargs):
        super().__init__(*args, **kwargs)

        self.children: list[Button] = []

        self.pages = pages
        self.num_pages = len(pages) if pages is not None else num_pages
        self.original_author = original_author
        self.guild = guild

        self.page_index = 0

        self.add_item(
            Button(
                style=ButtonStyle.blurple,
                label=Translatable("mrvn_api_views_paginator_button_first")))
        self.add_item(
            Button(style=ButtonStyle.gray,
                   label=Translatable("mrvn_api_views_paginator_button_prev")))
        self.add_item(
            Button(style=ButtonStyle.gray, label="N/A", disabled=True))
        self.add_item(
            Button(style=ButtonStyle.gray,
                   label=Translatable("mrvn_api_views_paginator_button_next")))
        self.add_item(
            Button(style=ButtonStyle.blurple,
                   label=Translatable("mrvn_api_views_paginator_button_last")))

        self.message = None
Example #2
0
class SettingGuildLanguage(GuildSetting):
    key = "guild_lang"
    description = Translatable("mrvn_api_setting_guild_language_desc")
    category = mrvn_category

    value_field = fields.TextField(default="en")

    @property
    def value(self) -> any:
        return self.value_field

    @value.setter
    def value(self, new_value: any):
        if new_value not in translations.translations.keys():
            raise SettingsValueWriteError(Translatable("mrvn_api_setting_guild_language_error"))

        self.value_field = new_value
Example #3
0
class SettingMessageCmdPrefix(GuildSetting):
    key = "command_prefix"
    description = Translatable("mrvn_api_setting_message_cmd_prefix_desc")
    category = mrvn_category

    value_field = fields.CharField(default="!", max_length=1)

    @property
    def value(self) -> any:
        return self.value_field

    @value.setter
    def value(self, new_value: any):
        if new_value not in PREFIX_LIST:
            raise SettingsValueWriteError(Translatable("mrvn_api_setting_prefix_invalid"))

        self.value_field = new_value
Example #4
0
    def __init__(self):
        # Set the options that will be presented inside the dropdown
        options = [
            SelectOption(label=Translatable("beu_ext_sex_anal_name"),
                         description=Translatable("beu_ext_sex_anal_desc"),
                         emoji="🍑"),
            SelectOption(label=Translatable("beu_ext_sex_vaginal_name"),
                         description=Translatable("beu_ext_sex_vaginal_desc"),
                         emoji="🐱"),
            SelectOption(label=Translatable("beu_ext_sex_oral_name"),
                         description=Translatable("beu_ext_sex_oral_desc"),
                         emoji="😱"),
        ]

        # The placeholder is what will be shown when no option is chosen
        # The min and max values indicate we can only pick one of the three options
        # The options parameter defines the dropdown options. We defined this above
        super().__init__(
            placeholder=Translatable("beu_ext_sex_placeholder"),
            min_values=1,
            max_values=1,
            options=options,
        )
Example #5
0
async def get_monthly_messages(guild_id: int) -> Optional[dict[str, int]]:
    messages = {}

    for day in range(PLOT_DAYS_COUNT):
        date = datetime.date.today() - datetime.timedelta(days=day)

        entries = await StatsDailyGuildMessages.filter(guild_id=guild_id,
                                                       date=date)

        messages[f"{date.day}-{date.month}"] = 0 if not len(
            entries) else entries[0].count

    return {k: v for k, v in reversed(list(messages.items()))}


@stats.stats_group.command(
    description=Translatable("statistics_command_messages_desc"),
    name="messages")
async def messages_command(ctx: MrvnCommandContext):
    await ctx.defer()

    data = await get_monthly_messages(ctx.guild_id)
    legend_text = ctx.format("statistics_command_messages_legend",
                             ctx.guild.name)

    result = await asyncio.get_event_loop().run_in_executor(
        None, functools.partial(plot.get_plot, data, legend_text))

    await ctx.respond(file=File(result, filename="Chart.png"))
Example #6
0
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.command.option.parse_until_ends import ParseUntilEndsOption
from api.translation.translatable import Translatable
from extensions.search.commands.category import search_category
from extensions.search.cse import cse
from extensions.search.cse.search_type import SearchType
from impl import runtime


@runtime.bot.slash_command(category=search_category,
                           description=Translatable("search_command_img_desc"))
async def img(ctx: MrvnCommandContext, query: ParseUntilEndsOption(str)):
    await cse.search(ctx, query, SearchType.IMAGES)
Example #7
0
from tortoise import fields

from api.settings import settings
from api.settings.setting import GuildSetting, GlobalSetting
from api.settings.settings_category import SettingsCategory
from api.translation.translatable import Translatable

category = settings.add_category(
    SettingsCategory("beu_ext",
                     Translatable("beu_ext_settings_category_name")))


class GuildSettingTest(GuildSetting):
    key = "guild_setting_test"
    description = Translatable("beu_ext_setting_test_desc")
    category = category

    value_field = fields.IntField(default=12345)


class GlobalSettingTest(GlobalSetting):
    key = "global_setting_test"
    description = Translatable("beu_ext_setting_test_global_desc")
    category = category

    value_field = fields.TextField(default="Global setting default val")
Example #8
0
    async def get_page_contents(self) -> Union[str, Embed]:
        embed = styled_embed_generator.get_embed(Style.INFO, title=self.tr.format("std_command_help_embed_title",
                                                                                  self.category_name),
                                                 author=self.original_author,
                                                 guild=self.guild)
        page_commands = self.commands[(self.page_index * PAGE_SIZE):][:PAGE_SIZE]

        for command in page_commands:
            embed.add_field(name=runtime.bot.get_command_desc(command, self.tr),
                            value=runtime.bot.get_translatable_desc(command, self.tr),
                            inline=False)

        return embed


@runtime.bot.slash_command(category=categories.info, description=Translatable("std_command_cmds_desc"))
async def cmds(ctx: MrvnCommandContext):
    cat_commands = {}

    for cat in categories.categories:
        cat_commands[cat] = runtime.bot.get_category_commands(cat, ctx.guild_id)

    cat_commands = {k: v for k, v in sorted(cat_commands.items(), key=lambda item: len(item[1]), reverse=True)}

    items = [Button(label=f"{ctx.translate(cat.name)} ({len(items)})", disabled=not len(items),
                    style=ButtonStyle.blurple if len(items) else ButtonStyle.gray) for cat, items in
             cat_commands.items()]

    view = CategoryView(ctx, items, author=ctx.author, timeout=10)

    message = await ctx.respond(ctx.translate("std_command_help_choose_category"), view=view)
Example #9
0
class SettingEnableSafeSearch(GuildSetting):
    key = "safe_search"
    description = Translatable("search_setting_safe_search")
    category = search_category

    value_field = fields.BooleanField(default=False)
Example #10
0
class GuildSettingTest(GuildSetting):
    key = "guild_setting_test"
    description = Translatable("beu_ext_setting_test_desc")
    category = category

    value_field = fields.IntField(default=12345)
Example #11
0
        await self.entries[item_len].delete()

        status_update.start_task()

        item.style = ButtonStyle.gray
        item.disabled = True

        await self.message.edit(view=self)

    async def respond(self, ctx: MrvnCommandContext):
        self.message = await ctx.respond_embed(
            Style.INFO,
            title=ctx.translate("bot_status_command_remove_choose_status"),
            view=self)


@bot_status_group.command(
    description=Translatable("bot_status_command_remove_desc"))
async def remove(ctx: MrvnCommandContext):
    entries = await BotStatusEntry.filter()

    if not len(entries):
        await ctx.respond_embed(
            Style.ERROR, ctx.translate("bot_status_command_remove_no_entries"))

        return

    view = EntriesView(ctx, await BotStatusEntry.filter(), timeout=40)

    await view.respond(ctx)
Example #12
0
from tortoise import Model, fields

from api.command.const import PREFIX_LIST
from api.list_field import ListField
from api.settings import settings
from api.settings.exc import SettingsValueWriteError
from api.settings.setting import GuildSetting, GlobalSetting
from api.settings.settings_category import SettingsCategory
from api.translation import translations
from api.translation.translatable import Translatable

mrvn_category = settings.add_category(SettingsCategory("mrvn", Translatable("mrvn_api_settings_category_name")))


class MrvnUser(Model):
    user_id = fields.IntField(pk=True)
    is_owner = fields.BooleanField(default=False)


class CommandOverride(Model):
    command_name = fields.CharField(max_length=32)
    guild_id = fields.IntField()

    disabled = fields.BooleanField(default=False)
    discord_permissions = ListField[str](default=[])
    whitelist_channel_ids = ListField[int](default=[])
    prefix = fields.CharField(max_length=1, default="")

    class Meta:
        unique_together = (("command_name", "guild_id"), )
Example #13
0
    return command_names


command_option = Option(str, autocomplete=basic_autocomplete(command_searcher))
command_option.converter = CommandConverter()


@event_handler()
async def startup():
    global command_names

    command_names = set(
        [cmd.name for cmd in runtime.bot.application_commands if isinstance(cmd, (SlashCommand, SlashCommandGroup))])


@override_group.command(description=Translatable("std_command_override_info_desc"))
async def info(ctx: MrvnCommandContext, command: command_option):
    override = await CommandOverride.get_or_none(guild_id=ctx.guild_id, command_name=command.name)

    if not override:
        await ctx.respond_embed(Style.ERROR, ctx.translate("std_command_override_no_override"))

        return

    empty = ctx.translate("std_command_override_empty")

    enabled = not override.disabled
    prefix = override.prefix if len(override.prefix) else empty
    perm_list = ", ".join(override.discord_permissions) if len(override.discord_permissions) else empty
    channel_list = ", ".join([channel.mention if (channel := runtime.bot.get_channel(x)) else str(x) for x in
                              override.whitelist_channel_ids]) if len(override.whitelist_channel_ids) else empty
Example #14
0
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.embed.style import Style
from api.translation.translatable import Translatable
from extensions.statistics.commands import stats
from extensions.statistics.models import StatsCommandEntry, StatsUserCommandsEntry
from impl import runtime


def get_user_mention(user_id: int):
    user = runtime.bot.get_user(user_id)

    return user.mention if user else "N/A"


@stats.stats_group.command(description=Translatable("statistics_command_commands_desc"))
async def commands(ctx: MrvnCommandContext):
    await ctx.defer()

    command_entries = sorted(await StatsCommandEntry.filter(guild_id=ctx.guild_id), key=lambda k: k.count,
                             reverse=True)[:10]
    command_stats = "\n".join([f"**{x.command_name}** - `{x.count}`" for x in command_entries])

    user_entries = sorted(await StatsUserCommandsEntry.filter(guild_id=ctx.guild_id), key=lambda k: k.count,
                          reverse=True)[:10]
    user_stats = "\n".join([f"{get_user_mention(x.user_id)} - `{x.count}`" for x in user_entries])

    embed = ctx.get_embed(Style.INFO, title=ctx.translate("statistics_command_commands_title"))
    embed.description = f"""
{ctx.translate("statistics_command_commands_command_top")}
{command_stats}
{ctx.translate("statistics_command_commands_user_top")}
Example #15
0
from discord import Member, Forbidden

from api.command import categories
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.embed.style import Style
from api.translation.translatable import Translatable
from impl import runtime


@runtime.bot.slash_command(category=categories.moderation, description=Translatable("moderation_command_ban_desc"),
                           discord_permissions=["ban_members"])
async def ban(ctx: MrvnCommandContext, member: Member):
    if member == runtime.bot.user:
        await ctx.respond_embed(Style.ERROR, ctx.translate("moderation_cant_do_this_to_bot"))

        return
    elif member == ctx.author:
        await ctx.respond_embed(Style.ERROR, ctx.translate("moderation_cant_do_this_to_self"))

        return
    elif ctx.author.top_role.position < member.top_role.position or ctx.author.guild_permissions < member.guild_permissions:
        await ctx.respond_embed(Style.ERROR, ctx.translate("moderation_cant_do_this_to_this_user"))

        return

    try:
        await member.ban(delete_message_days=0)
    except Forbidden:
        await ctx.respond_embed(Style.ERROR, ctx.translate("moderation_bot_insufficient_perms"))
    else:
        await ctx.respond_embed(Style.OK, ctx.format("moderation_command_ban_success", member.mention))
Example #16
0
from discord import Option, Member, Forbidden

from api.command import categories
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.embed.style import Style
from api.translation.translatable import Translatable
from impl import runtime

# Note: it seems that purge in Pycord is broken and this command cannot be executed more than once for some reason.


@runtime.bot.slash_command(
    category=categories.moderation,
    description=Translatable("moderation_command_purge_desc"),
    discord_permissions=["manage_messages"])
async def purge(ctx: MrvnCommandContext,
                number: Option(int, min_value=1, max_value=200),
                member: Member = None):
    try:
        deleted = await ctx.channel.purge(
            limit=number,
            check=lambda msg: member is None or msg.author == member,
            bulk=True)
    except Forbidden:
        await ctx.respond_embed(
            Style.ERROR, ctx.translate("moderation_bot_insufficient_perms"))
    else:
        await ctx.respond_embed(
            Style.OK,
            ctx.format("moderation_command_purge_messages_removed",
                       ctx.author.mention, deleted))
Example #17
0
import aiohttp
from aiohttp import ClientTimeout
from bs4 import BeautifulSoup
from discord import Option, Attachment

from api.command import categories
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.embed.style import Style
from api.translation.translatable import Translatable
from impl import runtime

SERVICE_URL = "https://visionbot.ru/index.php"


@runtime.bot.slash_command(
    description=Translatable("vision_command_vision_desc"),
    category=categories.utility)
async def vision(ctx: MrvnCommandContext, image: Option(Attachment)):
    if not image.content_type.startswith("image"):
        await ctx.respond_embed(
            Style.ERROR,
            ctx.translate("vision_command_vision_invalid_content_type"))

        return

    await ctx.defer()

    session = aiohttp.ClientSession(timeout=ClientTimeout(20))

    try:
        response = await session.post(
Example #18
0
class GlobalSettingTest(GlobalSetting):
    key = "global_setting_test"
    description = Translatable("beu_ext_setting_test_global_desc")
    category = category

    value_field = fields.TextField(default="Global setting default val")
Example #19
0
            (f"{setting.key} [{value}]", ctx.translate(setting.description)))

    paginator = CmdsPaginator(ctx,
                              settings_list,
                              ctx.translate(category.name),
                              is_global=global_setting,
                              num_pages=num_pages,
                              timeout=30,
                              original_author=ctx.author,
                              guild=ctx.guild)

    await paginator.attach(message)


@settings_group.command(
    name="list", description=Translatable("std_command_settings_list_desc"))
async def list_cmd(ctx: MrvnCommandContext):
    await list_(ctx, False)


@settings_group.command(
    description=Translatable("std_command_settings_edit_desc"))
async def edit(ctx: MrvnCommandContext, key: Option(
    str, autocomplete=basic_autocomplete(setting_autocomplete)), value: str):
    await edit_(ctx, key, value, False)


@global_settings_group.command(
    name="list", description=Translatable("std_command_gl_settings_list_desc"))
async def list_cmd(ctx: MrvnCommandContext):
    await list_(ctx, True)
Example #20
0
    def value(self, new_value: any):
        if new_value not in translations.translations.keys():
            raise SettingsValueWriteError(Translatable("mrvn_api_setting_guild_language_error"))

        self.value_field = new_value
Example #21
0
from discord import SlashCommand, SlashCommandGroup

from api.command import categories
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.command.option.parse_until_ends import ParseUntilEndsOption
from api.embed.style import Style
from api.translation.translatable import Translatable
from impl import runtime


@runtime.bot.slash_command(category=categories.info,
                           description=Translatable("std_command_man_desc"))
async def man(ctx: MrvnCommandContext, cmd_name: ParseUntilEndsOption(str)):
    cmd_split = iter(cmd_name.split())

    name = next(cmd_split)

    for cmd in runtime.bot.application_commands:
        if isinstance(cmd, (SlashCommand, SlashCommandGroup)
                      ) and cmd.name == name and ctx.guild_id in cmd.guild_ids:
            command = cmd
            break
    else:
        await ctx.respond_embed(
            Style.ERROR, ctx.translate("std_command_help_command_not_found"))

        return

    root = command

    try:
Example #22
0
class SettingForceGuildLang(GuildSetting):
    key = "force_guild_lang"
    description = Translatable("mrvn_api_setting_force_guild_language_desc")
    category = mrvn_category

    value_field = fields.BooleanField(default=False)
Example #23
0
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.command.option.parse_until_ends import ParseUntilEndsOption
from api.translation.translatable import Translatable
from extensions.search.commands.category import search_category
from extensions.search.cse import cse
from extensions.search.cse.search_type import SearchType
from impl import runtime


@runtime.bot.slash_command(
    category=search_category,
    description=Translatable("search_command_google_desc"))
async def google(ctx: MrvnCommandContext, query: ParseUntilEndsOption(str)):
    await cse.search(ctx, query, SearchType.GOOGLE)
Example #24
0
class SettingEnableMessageCommands(GuildSetting):
    key = "message_commands"
    description = Translatable("mrvn_api_setting_enable_message_commands_desc")
    category = mrvn_category

    value_field = fields.BooleanField(default=True)
Example #25
0
from tortoise import fields

from api.settings import settings
from api.settings.setting import GuildSetting
from api.settings.settings_category import SettingsCategory
from api.translation.translatable import Translatable

search_category = settings.add_category(
    SettingsCategory("search", Translatable("search_category_name")))


class SettingEnableSafeSearch(GuildSetting):
    key = "safe_search"
    description = Translatable("search_setting_safe_search")
    category = search_category

    value_field = fields.BooleanField(default=False)
Example #26
0
    def value(self, new_value: any):
        if new_value not in PREFIX_LIST:
            raise SettingsValueWriteError(Translatable("mrvn_api_setting_prefix_invalid"))

        self.value_field = new_value
Example #27
0
    def __delitem__(self, name):
        del self.globals[name]


async def async_exec(code: str, globs, locs):
    d = MyGlobals(globs, locs)

    exec(
        f'async def __ex(): ' + ''.join(f'\n {line}'
                                        for line in code.split('\n')), d)

    return await d.globals.get("__ex")()


@runtime.bot.slash_command(
    description=Translatable("execute_command_execute_desc"), owners_only=True)
async def execute(ctx: MrvnCommandContext, code: ParseUntilEndsOption(str)):
    if ctx.interaction is None:
        if len((splitted := ctx.message.content.split("```"))) == 3:
            code = splitted[1].rstrip()
        else:
            await ctx.respond_embed(
                Style.ERROR,
                ctx.translate("execute_command_execute_invalid_format"))

            return

    await ctx.defer()

    with io.StringIO() as buf, redirect_stdout(buf):
        # noinspection PyBroadException
Example #28
0
class SettingAllowCommandsInDMs(GlobalSetting):
    key = "dm_commands"
    description = Translatable("mrvn_api_setting_allow_dm_commands")
    category = mrvn_category

    value_field = fields.BooleanField(default=False)
Example #29
0
from impl import runtime

TIME_DICT = {
    "s": 1,
    "m": 60,
    "h": 3600,
    "d": 86400,
    "w": 604800,
    "mo": 18144000,
    "y": 217728000
}


@runtime.bot.slash_command(
    category=categories.moderation,
    description=Translatable("moderation_command_mute_desc"),
    discord_permissions=["moderate_members"])
async def mute(ctx: MrvnCommandContext, member: Member, time: int,
               unit: Option(str,
                            choices=[
                                OptionChoice("Seconds", "s"),
                                OptionChoice("Minutes", "m"),
                                OptionChoice("Hours", "h"),
                                OptionChoice("Days", "d"),
                                OptionChoice("Weeks", "w"),
                                OptionChoice("Months", "mo"),
                                OptionChoice("Years", "y")
                            ])):
    if member == runtime.bot.user:
        await ctx.respond_embed(
            Style.ERROR, ctx.translate("moderation_cant_do_this_to_bot"))
Example #30
0
from api.command import categories
from api.command.command_category import CommandCategory
from api.command.context.mrvn_command_context import MrvnCommandContext
from api.command.option.parse_until_ends import ParseUntilEndsOption
from api.embed.style import Style
from api.event_handler.decorators import event_handler
from api.translation.translatable import Translatable
from impl import runtime
from . import components_test
from . import modal_test
from . import pages_test
from . import view_test2

test_category = categories.add_category(
    CommandCategory(Translatable("beu_ext_category_name")))


@event_handler()
async def on_startup():
    logging.info("Beu startup!")


@runtime.bot.slash_command(category=categories.debug)
async def test(ctx: MrvnCommandContext, arg_1: str, arg_2: str):
    """Test command"""

    await ctx.respond_embed(Style.INFO, desc=f"arg_1: {arg_1}\narg_2: {arg_2}")


@runtime.bot.slash_command(category=categories.debug)