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
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
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
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, )
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"))
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)
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")
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)
class SettingEnableSafeSearch(GuildSetting): key = "safe_search" description = Translatable("search_setting_safe_search") category = search_category value_field = fields.BooleanField(default=False)
class GuildSettingTest(GuildSetting): key = "guild_setting_test" description = Translatable("beu_ext_setting_test_desc") category = category value_field = fields.IntField(default=12345)
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)
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"), )
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
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")}
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))
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))
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(
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")
(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)
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
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:
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)
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)
class SettingEnableMessageCommands(GuildSetting): key = "message_commands" description = Translatable("mrvn_api_setting_enable_message_commands_desc") category = mrvn_category value_field = fields.BooleanField(default=True)
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)
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
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
class SettingAllowCommandsInDMs(GlobalSetting): key = "dm_commands" description = Translatable("mrvn_api_setting_allow_dm_commands") category = mrvn_category value_field = fields.BooleanField(default=False)
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"))
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)