Mostly functioning, quirks with command execution

This commit is contained in:
Zeva Rose 2023-03-16 00:42:34 -06:00
parent 9143b8f4b4
commit 7e53127e19
37 changed files with 1111 additions and 918 deletions

View file

@ -4,6 +4,7 @@ from functools import partial
from typing import Any from typing import Any
import jurigged import jurigged
from statipy.db import init_db
from interactions import Intents from interactions import Intents
from jarvis_core.db import connect from jarvis_core.db import connect
from jarvis_core.log import get_logger from jarvis_core.log import get_logger
@ -65,12 +66,14 @@ async def run() -> None:
logger.addHandler(file_handler) logger.addHandler(file_handler)
# Configure client # Configure client
intents = Intents.DEFAULT | Intents.MESSAGES | Intents.GUILD_MEMBERS | Intents.GUILD_MESSAGE_CONTENT intents = Intents.DEFAULT | Intents.MESSAGES | Intents.GUILD_MEMBERS | Intents.GUILD_MESSAGES
redis_config = jconfig.redis.copy() redis_config = jconfig.redis.copy()
redis_host = redis_config.pop("host") redis_host = redis_config.pop("host")
redis = await aioredis.from_url(redis_host, decode_responses=True, **redis_config) redis = await aioredis.from_url(redis_host, decode_responses=True, **redis_config)
await init_db(**jconfig.mongo["connect"])
jarvis = Jarvis( jarvis = Jarvis(
intents=intents, intents=intents,
sync_interactions=jconfig.sync, sync_interactions=jconfig.sync,
@ -99,8 +102,9 @@ async def run() -> None:
for extension in get_extensions(cogs_path): for extension in get_extensions(cogs_path):
jarvis.load_extension(extension) jarvis.load_extension(extension)
logger.debug("Loaded %s", extension) logger.debug("Loaded %s", extension)
logger.debug("Loading nafftrack")
jarvis.load_extension("nafftrack.extension") logger.debug("Loading statipy")
jarvis.load_extension("statipy.ext")
jarvis.max_messages = jconfig.max_messages jarvis.max_messages = jconfig.max_messages
logger.debug("Running JARVIS") logger.debug("Running JARVIS")

View file

@ -6,6 +6,7 @@ from interactions import Client
from interactions.ext.prefixed_commands.context import PrefixedContext from interactions.ext.prefixed_commands.context import PrefixedContext
from interactions.models.internal.context import BaseContext, InteractionContext from interactions.models.internal.context import BaseContext, InteractionContext
from jarvis_core.util.ansi import Fore, Format, fmt from jarvis_core.util.ansi import Fore, Format, fmt
from statipy import StatipyClient
from jarvis.client.errors import ErrorMixin from jarvis.client.errors import ErrorMixin
from jarvis.client.events import EventMixin from jarvis.client.events import EventMixin
@ -19,7 +20,7 @@ VAL_FMT = fmt(Fore.WHITE)
CMD_FMT = fmt(Fore.GREEN, Format.BOLD) CMD_FMT = fmt(Fore.GREEN, Format.BOLD)
class Jarvis(Client, ErrorMixin, EventMixin, TaskMixin): class Jarvis(StatipyClient, ErrorMixin, EventMixin, TaskMixin):
def __init__(self, redis: "aioredis.Redis", *args, **kwargs): # noqa: ANN002 ANN003 def __init__(self, redis: "aioredis.Redis", *args, **kwargs): # noqa: ANN002 ANN003
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.redis = redis self.redis = redis

View file

@ -18,7 +18,7 @@ DEFAULT_SITE = "https://paste.zevs.me"
ERROR_MSG = """ ERROR_MSG = """
Command Information: Command Information:
Guild: {guild_name} Guild: {guild_name}
Name: {invoked_name} Name: {invoke_target}
Args: Args:
{arg_str} {arg_str}
@ -74,7 +74,7 @@ class ErrorMixin:
full_message = ERROR_MSG.format( full_message = ERROR_MSG.format(
guild_name=ctx.guild.name, guild_name=ctx.guild.name,
error_time=error_time, error_time=error_time,
invoked_name=name, invoke_target=name,
arg_str=arg_str, arg_str=arg_str,
callback_args=callback_args, callback_args=callback_args,
callback_kwargs=callback_kwargs, callback_kwargs=callback_kwargs,

View file

@ -2,6 +2,7 @@
import asyncio import asyncio
from aiohttp import ClientSession from aiohttp import ClientSession
from beanie.operators import Set
from interactions import listen from interactions import listen
from interactions.ext.prefixed_commands.context import PrefixedContext from interactions.ext.prefixed_commands.context import PrefixedContext
from interactions.models.discord.channel import DMChannel from interactions.models.discord.channel import DMChannel
@ -11,12 +12,12 @@ from interactions.models.internal.context import BaseContext, InteractionContext
from jarvis_core.db import q from jarvis_core.db import q
from jarvis_core.db.models import Reminder, Setting from jarvis_core.db.models import Reminder, Setting
from jarvis_core.util.ansi import RESET, Fore, Format, fmt from jarvis_core.util.ansi import RESET, Fore, Format, fmt
from statipy.db import StaticStat
from jarvis import const from jarvis import const
from jarvis.client.events.components import ComponentEventMixin from jarvis.client.events.components import ComponentEventMixin
from jarvis.client.events.member import MemberEventMixin from jarvis.client.events.member import MemberEventMixin
from jarvis.client.events.message import MessageEventMixin from jarvis.client.events.message import MessageEventMixin
from jarvis.tracking import jarvis_info
from jarvis.utils import build_embed from jarvis.utils import build_embed
KEY_FMT = fmt(Fore.GRAY) KEY_FMT = fmt(Fore.GRAY)
@ -27,9 +28,11 @@ CMD_FMT = fmt(Fore.GREEN, Format.BOLD)
class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin): class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin):
async def _chunk_all(self) -> None: async def _chunk_all(self) -> None:
"""Chunk all guilds.""" """Chunk all guilds."""
for guild in self.guilds: self.logger.warn("Deprecated function, nothing will happen")
self.logger.debug(f"Chunking guild {guild.name} <{guild.id}>") # for guild in self.guilds:
await guild.chunk_guild() # if not guild.chunked.is_set():
# self.logger.debug(f"Chunking guild {guild.name} <{guild.id}>")
# await guild.chunk_guild()
async def _sync_domains(self) -> None: async def _sync_domains(self) -> None:
self.logger.debug("Loading phishing domains") self.logger.debug("Loading phishing domains")
@ -42,7 +45,20 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin):
@listen() @listen()
async def on_startup(self) -> None: async def on_startup(self) -> None:
"""NAFF on_startup override. Prometheus info generated here.""" """NAFF on_startup override. Prometheus info generated here."""
jarvis_info.info({"version": const.__version__}) await StaticStat.find_one(StaticStat.name == "jarvis_version", StaticStat.client_id == self.user.id).upsert(
Set(
{
StaticStat.client_name: self.client_name,
StaticStat.value: const.__version__,
}
),
on_insert=StaticStat(
name="jarvis_version",
client_id=self.user.id,
client_name=self.client_name,
value=const.__version__,
),
)
try: try:
if not self.synced: if not self.synced:
await self._sync_domains() await self._sync_domains()

View file

@ -3,13 +3,14 @@ import re
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from aiohttp import ClientSession from aiohttp import ClientSession
from beanie.operators import Inc, Set
from interactions import listen from interactions import listen
from interactions.api.events.discord import MessageCreate, MessageDelete, MessageUpdate from interactions.api.events.discord import MessageCreate, MessageDelete, MessageUpdate
from interactions.client.utils.misc_utils import find_all from interactions.client.utils.misc_utils import find_all
from interactions.models.discord.channel import DMChannel, GuildText from interactions.models.discord.channel import DMChannel, GuildText
from interactions.models.discord.components import ActionRow, Button from interactions.models.discord.components import ActionRow, Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles, Permissions from interactions.models.discord.enums import ButtonStyle, Permissions
from interactions.models.discord.message import Message from interactions.models.discord.message import Message
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from jarvis_core.db import q from jarvis_core.db import q
@ -24,11 +25,12 @@ from jarvis_core.db.models import (
Warning, Warning,
) )
from jarvis_core.filters import invites, url from jarvis_core.filters import invites, url
from statipy.db import Stat
from jarvis.branding import get_command_color from jarvis.branding import get_command_color
from jarvis.embeds.admin import warning_embed from jarvis.embeds.admin import warning_embed
from jarvis.tracking import malicious_tracker, warnings_tracker
from jarvis.utils import build_embed from jarvis.utils import build_embed
from jarvis.tracking import WarningMetadata
class MessageEventMixin: class MessageEventMixin:
@ -99,8 +101,16 @@ class MessageEventMixin:
reason="Sent an invite link", reason="Sent an invite link",
user=message.author.id, user=message.author.id,
).commit() ).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="invite",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
embed = warning_embed(message.author, "Sent an invite link", self.user) embed = warning_embed(message.author, "Sent an invite link", self.user)
try: try:
await message.channel.send(embeds=embed) await message.channel.send(embeds=embed)
@ -123,8 +133,16 @@ class MessageEventMixin:
reason="Sent a message with a filtered word", reason="Sent a message with a filtered word",
user=message.author.id, user=message.author.id,
).commit() ).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="filter",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
embed = warning_embed(message.author, "Sent a message with a filtered word", self.user) embed = warning_embed(message.author, "Sent a message with a filtered word", self.user)
try: try:
await message.reply(embeds=embed) await message.reply(embeds=embed)
@ -169,8 +187,16 @@ class MessageEventMixin:
reason="Mass Mention", reason="Mass Mention",
user=message.author.id, user=message.author.id,
).commit() ).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="massmention",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
embed = warning_embed(message.author, "Mass Mention", self.user) embed = warning_embed(message.author, "Mass Mention", self.user)
try: try:
await message.channel.send(embeds=embed) await message.channel.send(embeds=embed)
@ -233,8 +259,16 @@ class MessageEventMixin:
reason="Pinged a blocked role/user with a blocked role", reason="Pinged a blocked role/user with a blocked role",
user=message.author.id, user=message.author.id,
).commit() ).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="roleping",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
embed = warning_embed(message.author, "Pinged a blocked role/user with a blocked role", self.user) embed = warning_embed(message.author, "Pinged a blocked role/user with a blocked role", self.user)
try: try:
await message.channel.send(embeds=embed) await message.channel.send(embeds=embed)
@ -261,8 +295,16 @@ class MessageEventMixin:
reason="Phishing URL", reason="Phishing URL",
user=message.author.id, user=message.author.id,
).commit() ).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="phishing",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
embed = warning_embed(message.author, "Phishing URL", self.user) embed = warning_embed(message.author, "Phishing URL", self.user)
try: try:
await message.channel.send(embeds=embed) await message.channel.send(embeds=embed)
@ -272,8 +314,6 @@ class MessageEventMixin:
await message.delete() await message.delete()
except Exception: except Exception:
self.logger.warn("Failed to delete malicious message") self.logger.warn("Failed to delete malicious message")
tracker = malicious_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
if not pl or not pl.confirmed: if not pl or not pl.confirmed:
if not pl: if not pl:
@ -286,8 +326,8 @@ class MessageEventMixin:
fields=[EmbedField(name="URL", value=m)], fields=[EmbedField(name="URL", value=m)],
) )
valid_button = Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}") valid_button = Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}")
invalid_button = Button(style=ButtonStyles.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}") invalid_button = Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}")
channel = await self.fetch_channel(1026918337554423868) channel = await self.fetch_channel(1026918337554423868)
@ -331,8 +371,16 @@ class MessageEventMixin:
reason="Unsafe URL", reason="Unsafe URL",
user=message.author.id, user=message.author.id,
).commit() ).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="malicious",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
reasons = ", ".join(f"{m['source']}: {m['type']}" for m in data["matches"]) reasons = ", ".join(f"{m['source']}: {m['type']}" for m in data["matches"])
embed = warning_embed(message.author, reasons, self.user) embed = warning_embed(message.author, reasons, self.user)
try: try:
@ -343,8 +391,6 @@ class MessageEventMixin:
await message.delete() await message.delete()
except Exception: except Exception:
self.logger.warn("Failed to delete malicious message") self.logger.warn("Failed to delete malicious message")
tracker = malicious_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
if not pl or not pl.confirmed: if not pl or not pl.confirmed:
if not pl: if not pl:
@ -357,8 +403,8 @@ class MessageEventMixin:
fields=[EmbedField(name="URL", value=m)], fields=[EmbedField(name="URL", value=m)],
) )
valid_button = Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}") valid_button = Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}")
invalid_button = Button(style=ButtonStyles.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}") invalid_button = Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}")
channel = await self.fetch_channel(1026918337554423868) channel = await self.fetch_channel(1026918337554423868)

View file

@ -7,7 +7,7 @@ from interactions import Client, Extension, InteractionContext, Permissions
from interactions.client.utils.misc_utils import find from interactions.client.utils.misc_utils import find
from interactions.models.discord.channel import GuildText from interactions.models.discord.channel import GuildText
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -81,11 +81,11 @@ class AutoReactCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Autoreact channel to add emote to", description="Autoreact channel to add emote to",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@slash_option(name="thread", description="Create a thread?", opt_type=OptionTypes.BOOLEAN, required=False) @slash_option(name="thread", description="Create a thread?", opt_type=OptionType.BOOLEAN, required=False)
@slash_option(name="emote", description="Emote to add", opt_type=OptionTypes.STRING, required=False) @slash_option(name="emote", description="Emote to add", opt_type=OptionType.STRING, required=False)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _autoreact_add( async def _autoreact_add(
self, ctx: InteractionContext, channel: GuildText, thread: bool = True, emote: str = None self, ctx: InteractionContext, channel: GuildText, thread: bool = True, emote: str = None
@ -138,13 +138,13 @@ class AutoReactCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Autoreact channel to remove emote from", description="Autoreact channel to remove emote from",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@slash_option( @slash_option(
name="emote", name="emote",
description="Emote to remove (use all to delete)", description="Emote to remove (use all to delete)",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -179,7 +179,7 @@ class AutoReactCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to remove autoreact from", description="Channel to remove autoreact from",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -197,7 +197,7 @@ class AutoReactCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Autoreact channel to list", description="Autoreact channel to list",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None: async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None:

View file

@ -8,7 +8,7 @@ from interactions.ext.paginators import Paginator
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.user import User from interactions.models.discord.user import User
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
SlashCommandChoice, SlashCommandChoice,
slash_command, slash_command,
@ -84,12 +84,12 @@ class BanCog(ModcaseCog):
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@slash_command(name="ban", description="Ban a user") @slash_command(name="ban", description="Ban a user")
@slash_option(name="user", description="User to ban", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to ban", opt_type=OptionType.USER, required=True)
@slash_option(name="reason", description="Ban reason", opt_type=OptionTypes.STRING, required=True) @slash_option(name="reason", description="Ban reason", opt_type=OptionType.STRING, required=True)
@slash_option( @slash_option(
name="btype", name="btype",
description="Ban type", description="Ban type",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
choices=[ choices=[
SlashCommandChoice(name="Permanent", value="perm"), SlashCommandChoice(name="Permanent", value="perm"),
@ -100,13 +100,13 @@ class BanCog(ModcaseCog):
@slash_option( @slash_option(
name="duration", name="duration",
description="Temp ban duration in hours", description="Temp ban duration in hours",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@slash_option( @slash_option(
name="delete_history", name="delete_history",
description="Delete message history, format: 1w 3d 7h 5m 20s", description="Delete message history, format: 1w 3d 7h 5m 20s",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
@ -197,8 +197,8 @@ class BanCog(ModcaseCog):
await ctx.guild.unban(user, reason="Ban was softban") await ctx.guild.unban(user, reason="Ban was softban")
@slash_command(name="unban", description="Unban a user") @slash_command(name="unban", description="Unban a user")
@slash_option(name="user", description="User to unban", opt_type=OptionTypes.STRING, required=True) @slash_option(name="user", description="User to unban", opt_type=OptionType.STRING, required=True)
@slash_option(name="reason", description="Unban reason", opt_type=OptionTypes.STRING, required=True) @slash_option(name="reason", description="Unban reason", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _unban( async def _unban(
self, self,
@ -288,7 +288,7 @@ class BanCog(ModcaseCog):
@slash_option( @slash_option(
name="btype", name="btype",
description="Ban type", description="Ban type",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
choices=[ choices=[
SlashCommandChoice(name="All", value=0), SlashCommandChoice(name="All", value=0),
@ -300,7 +300,7 @@ class BanCog(ModcaseCog):
@slash_option( @slash_option(
name="active", name="active",
description="Active bans", description="Active bans",
opt_type=OptionTypes.BOOLEAN, opt_type=OptionType.BOOLEAN,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))

View file

@ -13,7 +13,7 @@ from interactions import (
) )
from interactions.models.discord.modal import InputText, Modal, TextStyles from interactions.models.discord.modal import InputText, Modal, TextStyles
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -88,7 +88,7 @@ class FilterCog(Extension):
filter_ = SlashCommand(name="filter", description="Manage keyword filters") filter_ = SlashCommand(name="filter", description="Manage keyword filters")
@filter_.subcommand(sub_cmd_name="create", sub_cmd_description="Create a new filter") @filter_.subcommand(sub_cmd_name="create", sub_cmd_description="Create a new filter")
@slash_option(name="name", description="Name of new filter", required=True, opt_type=OptionTypes.STRING) @slash_option(name="name", description="Name of new filter", required=True, opt_type=OptionType.STRING)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _filter_create(self, ctx: InteractionContext, name: str) -> None: async def _filter_create(self, ctx: InteractionContext, name: str) -> None:
return await self._edit_filter(ctx, name) return await self._edit_filter(ctx, name)
@ -98,7 +98,7 @@ class FilterCog(Extension):
name="name", name="name",
description="Filter to edit", description="Filter to edit",
autocomplete=True, autocomplete=True,
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -110,7 +110,7 @@ class FilterCog(Extension):
name="name", name="name",
description="Filter to view", description="Filter to view",
autocomplete=True, autocomplete=True,
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
async def _filter_view(self, ctx: InteractionContext, name: str) -> None: async def _filter_view(self, ctx: InteractionContext, name: str) -> None:
@ -128,7 +128,7 @@ class FilterCog(Extension):
name="name", name="name",
description="Filter to delete", description="Filter to delete",
autocomplete=True, autocomplete=True,
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))

View file

@ -2,7 +2,7 @@
from interactions import InteractionContext, Permissions from interactions import InteractionContext, Permissions
from interactions.models.discord.user import User from interactions.models.discord.user import User
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
slash_command, slash_command,
slash_option, slash_option,
) )
@ -18,8 +18,8 @@ class KickCog(ModcaseCog):
"""JARVIS KickCog.""" """JARVIS KickCog."""
@slash_command(name="kick", description="Kick a user") @slash_command(name="kick", description="Kick a user")
@slash_option(name="user", description="User to kick", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to kick", opt_type=OptionType.USER, required=True)
@slash_option(name="reason", description="Kick reason", opt_type=OptionTypes.STRING, required=True) @slash_option(name="reason", description="Kick reason", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _kick(self, ctx: InteractionContext, user: User, reason: str) -> None: async def _kick(self, ctx: InteractionContext, user: User, reason: str) -> None:
if not user or user == ctx.author: if not user or user == ctx.author:

View file

@ -7,7 +7,7 @@ from interactions.client.utils.misc_utils import get
from interactions.models.discord.channel import GuildText, GuildVoice from interactions.models.discord.channel import GuildText, GuildVoice
from interactions.models.discord.enums import Permissions from interactions.models.discord.enums import Permissions
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
slash_command, slash_command,
slash_option, slash_option,
) )
@ -89,7 +89,7 @@ class LockCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to unlock", description="Channel to unlock",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_CHANNELS)) @check(admin_or_permissions(Permissions.MANAGE_CHANNELS))

View file

@ -8,7 +8,7 @@ from interactions.models.discord.enums import Permissions
from interactions.models.discord.guild import Guild from interactions.models.discord.guild import Guild
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -108,11 +108,11 @@ class LockdownCog(Extension):
sub_cmd_name="start", sub_cmd_name="start",
sub_cmd_description="Lockdown the server", sub_cmd_description="Lockdown the server",
) )
@slash_option(name="reason", description="Lockdown reason", opt_type=OptionTypes.STRING, required=True) @slash_option(name="reason", description="Lockdown reason", opt_type=OptionType.STRING, required=True)
@slash_option( @slash_option(
name="duration", name="duration",
description="Duration in minutes", description="Duration in minutes",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_CHANNELS)) @check(admin_or_permissions(Permissions.MANAGE_CHANNELS))

View file

@ -6,7 +6,7 @@ from interactions.ext.paginators import Paginator
from interactions.models.discord.embed import Embed, EmbedField from interactions.models.discord.embed import Embed, EmbedField
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -184,13 +184,13 @@ class CaseCog(Extension):
@slash_option( @slash_option(
name="user", name="user",
description="User to filter cases to", description="User to filter cases to",
opt_type=OptionTypes.USER, opt_type=OptionType.USER,
required=False, required=False,
) )
@slash_option( @slash_option(
name="closed", name="closed",
description="Include closed cases", description="Include closed cases",
opt_type=OptionTypes.BOOLEAN, opt_type=OptionType.BOOLEAN,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
@ -214,7 +214,7 @@ class CaseCog(Extension):
show = case.group(name="show", description="Show information about a specific case") show = case.group(name="show", description="Show information about a specific case")
@show.subcommand(sub_cmd_name="summary", sub_cmd_description="Summarize a specific case") @show.subcommand(sub_cmd_name="summary", sub_cmd_description="Summarize a specific case")
@slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_show_summary(self, ctx: InteractionContext, cid: str) -> None: async def _case_show_summary(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -226,7 +226,7 @@ class CaseCog(Extension):
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@show.subcommand(sub_cmd_name="actions", sub_cmd_description="Get case actions") @show.subcommand(sub_cmd_name="actions", sub_cmd_description="Get case actions")
@slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_show_actions(self, ctx: InteractionContext, cid: str) -> None: async def _case_show_actions(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -239,7 +239,7 @@ class CaseCog(Extension):
await paginator.send(ctx) await paginator.send(ctx)
@case.subcommand(sub_cmd_name="close", sub_cmd_description="Show a specific case") @case.subcommand(sub_cmd_name="close", sub_cmd_description="Show a specific case")
@slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_close(self, ctx: InteractionContext, cid: str) -> None: async def _case_close(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -254,7 +254,7 @@ class CaseCog(Extension):
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@case.subcommand(sub_cmd_name="repoen", sub_cmd_description="Reopen a specific case") @case.subcommand(sub_cmd_name="repoen", sub_cmd_description="Reopen a specific case")
@slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_reopen(self, ctx: InteractionContext, cid: str) -> None: async def _case_reopen(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -269,8 +269,8 @@ class CaseCog(Extension):
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@case.subcommand(sub_cmd_name="note", sub_cmd_description="Add a note to a specific case") @case.subcommand(sub_cmd_name="note", sub_cmd_description="Add a note to a specific case")
@slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@slash_option(name="note", description="Note to add", opt_type=OptionTypes.STRING, required=True) @slash_option(name="note", description="Note to add", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None: async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -295,8 +295,8 @@ class CaseCog(Extension):
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@case.subcommand(sub_cmd_name="new", sub_cmd_description="Open a new case") @case.subcommand(sub_cmd_name="new", sub_cmd_description="Open a new case")
@slash_option(name="user", description="Target user", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="Target user", opt_type=OptionType.USER, required=True)
@slash_option(name="note", description="Note to add", opt_type=OptionTypes.STRING, required=True) @slash_option(name="note", description="Note to add", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None: async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, user=user.id, open=True)) case = await Modlog.find_one(q(guild=ctx.guild.id, user=user.id, open=True))

View file

@ -9,8 +9,8 @@ from interactions.client.errors import Forbidden
from interactions.models.discord.modal import InputText, Modal, TextStyles from interactions.models.discord.modal import InputText, Modal, TextStyles
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
CommandTypes, CommandType,
OptionTypes, OptionType,
SlashCommandChoice, SlashCommandChoice,
context_menu, context_menu,
slash_command, slash_command,
@ -41,7 +41,7 @@ class MuteCog(ModcaseCog):
return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild) return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild)
@context_menu(name="Mute User", context_type=CommandTypes.USER) @context_menu(name="Mute User", context_type=CommandType.USER)
@check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS)) @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS))
async def _timeout_cm(self, ctx: InteractionContext) -> None: async def _timeout_cm(self, ctx: InteractionContext) -> None:
modal = Modal( modal = Modal(
@ -103,23 +103,23 @@ class MuteCog(ModcaseCog):
await response.send("Unable to mute this user", ephemeral=True) await response.send("Unable to mute this user", ephemeral=True)
@slash_command(name="mute", description="Mute a user") @slash_command(name="mute", description="Mute a user")
@slash_option(name="user", description="User to mute", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to mute", opt_type=OptionType.USER, required=True)
@slash_option( @slash_option(
name="reason", name="reason",
description="Reason for mute", description="Reason for mute",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@slash_option( @slash_option(
name="time", name="time",
description="Duration of mute, default 1", description="Duration of mute, default 1",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@slash_option( @slash_option(
name="scale", name="scale",
description="Time scale, default Hour(s)", description="Time scale, default Hour(s)",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
choices=[ choices=[
SlashCommandChoice(name="Minute(s)", value=1), SlashCommandChoice(name="Minute(s)", value=1),
@ -159,8 +159,8 @@ class MuteCog(ModcaseCog):
await ctx.send("Unable to mute this user", ephemeral=True) await ctx.send("Unable to mute this user", ephemeral=True)
@slash_command(name="unmute", description="Unmute a user") @slash_command(name="unmute", description="Unmute a user")
@slash_option(name="user", description="User to unmute", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to unmute", opt_type=OptionType.USER, required=True)
@slash_option(name="reason", description="Reason for unmute", opt_type=OptionTypes.STRING, required=True) @slash_option(name="reason", description="Reason for unmute", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS)) @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS))
async def _unmute(self, ctx: InteractionContext, user: Member, reason: str) -> None: async def _unmute(self, ctx: InteractionContext, user: Member, reason: str) -> None:
if ( if (

View file

@ -4,7 +4,7 @@ import logging
from interactions import Client, Extension, InteractionContext, Permissions from interactions import Client, Extension, InteractionContext, Permissions
from interactions.models.discord.channel import GuildText from interactions.models.discord.channel import GuildText
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
slash_command, slash_command,
slash_option, slash_option,
) )
@ -26,7 +26,7 @@ class PurgeCog(Extension):
@slash_option( @slash_option(
name="amount", name="amount",
description="Amount of messages to purge, default 10", description="Amount of messages to purge, default 10",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -51,13 +51,13 @@ class PurgeCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to autopurge", description="Channel to autopurge",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@slash_option( @slash_option(
name="delay", name="delay",
description="Seconds to keep message before purge, default 30", description="Seconds to keep message before purge, default 30",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -90,7 +90,7 @@ class PurgeCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to remove from autopurge", description="Channel to remove from autopurge",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -110,13 +110,13 @@ class PurgeCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to update", description="Channel to update",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@slash_option( @slash_option(
name="delay", name="delay",
description="New time to save", description="New time to save",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))

View file

@ -8,7 +8,7 @@ from interactions.models.discord.embed import EmbedField
from interactions.models.discord.role import Role from interactions.models.discord.role import Role
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -33,7 +33,7 @@ class RolepingCog(Extension):
sub_cmd_name="add", sub_cmd_name="add",
sub_cmd_description="Add a role to roleping", sub_cmd_description="Add a role to roleping",
) )
@slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Role to add", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None: async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
@ -55,7 +55,7 @@ class RolepingCog(Extension):
await ctx.send(f"Role `{role.name}` added to roleping.") await ctx.send(f"Role `{role.name}` added to roleping.")
@roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role") @roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role")
@slash_option(name="role", description="Role to remove", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Role to remove", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None: async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
@ -133,8 +133,8 @@ class RolepingCog(Extension):
sub_cmd_name="user", sub_cmd_name="user",
sub_cmd_description="Add a user as a bypass to a roleping", sub_cmd_description="Add a user as a bypass to a roleping",
) )
@slash_option(name="bypass", description="User to add", opt_type=OptionTypes.USER, required=True) @slash_option(name="bypass", description="User to add", opt_type=OptionType.USER, required=True)
@slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Rolepinged role", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None: async def _roleping_bypass_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
@ -170,8 +170,8 @@ class RolepingCog(Extension):
sub_cmd_name="role", sub_cmd_name="role",
sub_cmd_description="Add a role as a bypass to roleping", sub_cmd_description="Add a role as a bypass to roleping",
) )
@slash_option(name="bypass", description="Role to add", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="bypass", description="Role to add", opt_type=OptionType.ROLE, required=True)
@slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Rolepinged role", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None: async def _roleping_bypass_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None:
if bypass.id == ctx.guild.id: if bypass.id == ctx.guild.id:
@ -203,8 +203,8 @@ class RolepingCog(Extension):
sub_cmd_name="user", sub_cmd_name="user",
sub_cmd_description="Remove a bypass from a roleping (restoring it)", sub_cmd_description="Remove a bypass from a roleping (restoring it)",
) )
@slash_option(name="bypass", description="User to remove", opt_type=OptionTypes.USER, required=True) @slash_option(name="bypass", description="User to remove", opt_type=OptionType.USER, required=True)
@slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Rolepinged role", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_restore_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None: async def _roleping_restore_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None:
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
@ -224,8 +224,8 @@ class RolepingCog(Extension):
sub_cmd_name="role", sub_cmd_name="role",
sub_cmd_description="Remove a bypass from a roleping (restoring it)", sub_cmd_description="Remove a bypass from a roleping (restoring it)",
) )
@slash_option(name="bypass", description="Role to remove", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="bypass", description="Role to remove", opt_type=OptionType.ROLE, required=True)
@slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Rolepinged role", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_restore_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None: async def _roleping_restore_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None:
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))

View file

@ -5,12 +5,12 @@ from typing import Any
from interactions import AutocompleteContext, Client, Extension, InteractionContext from interactions import AutocompleteContext, Client, Extension, InteractionContext
from interactions.models.discord.channel import GuildText from interactions.models.discord.channel import GuildText
from interactions.models.discord.components import ActionRow, Button, ButtonStyles from interactions.models.discord.components import ActionRow, Button, ButtonStyle
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import Permissions from interactions.models.discord.enums import Permissions
from interactions.models.discord.role import Role from interactions.models.discord.role import Role
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -55,7 +55,7 @@ class SettingsCog(Extension):
sub_cmd_name="modlog", sub_cmd_name="modlog",
sub_cmd_description="Set Moglod channel", sub_cmd_description="Set Moglod channel",
) )
@slash_option(name="channel", description="ModLog Channel", opt_type=OptionTypes.CHANNEL, required=True) @slash_option(name="channel", description="ModLog Channel", opt_type=OptionType.CHANNEL, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _set_modlog(self, ctx: InteractionContext, channel: GuildText) -> None: async def _set_modlog(self, ctx: InteractionContext, channel: GuildText) -> None:
if not isinstance(channel, GuildText): if not isinstance(channel, GuildText):
@ -71,7 +71,7 @@ class SettingsCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Activitylog Channel", description="Activitylog Channel",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -86,7 +86,7 @@ class SettingsCog(Extension):
@slash_option( @slash_option(
name="amount", name="amount",
description="Amount of mentions (0 to disable)", description="Amount of mentions (0 to disable)",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -96,7 +96,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. New massmention limit is {amount}") await ctx.send(f"Settings applied. New massmention limit is {amount}")
@set_.subcommand(sub_cmd_name="verified", sub_cmd_description="Set verified role") @set_.subcommand(sub_cmd_name="verified", sub_cmd_description="Set verified role")
@slash_option(name="role", description="Verified role", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Verified role", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _set_verified(self, ctx: InteractionContext, role: Role) -> None: async def _set_verified(self, ctx: InteractionContext, role: Role) -> None:
if role.id == ctx.guild.id: if role.id == ctx.guild.id:
@ -113,7 +113,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. New verified role is `{role.name}`") await ctx.send(f"Settings applied. New verified role is `{role.name}`")
@set_.subcommand(sub_cmd_name="unverified", sub_cmd_description="Set unverified role") @set_.subcommand(sub_cmd_name="unverified", sub_cmd_description="Set unverified role")
@slash_option(name="role", description="Unverified role", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Unverified role", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _set_unverified(self, ctx: InteractionContext, role: Role) -> None: async def _set_unverified(self, ctx: InteractionContext, role: Role) -> None:
if role.id == ctx.guild.id: if role.id == ctx.guild.id:
@ -130,7 +130,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. New unverified role is `{role.name}`") await ctx.send(f"Settings applied. New unverified role is `{role.name}`")
@set_.subcommand(sub_cmd_name="noinvite", sub_cmd_description="Set if invite deletion should happen") @set_.subcommand(sub_cmd_name="noinvite", sub_cmd_description="Set if invite deletion should happen")
@slash_option(name="active", description="Active?", opt_type=OptionTypes.BOOLEAN, required=True) @slash_option(name="active", description="Active?", opt_type=OptionType.BOOLEAN, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _set_invitedel(self, ctx: InteractionContext, active: bool) -> None: async def _set_invitedel(self, ctx: InteractionContext, active: bool) -> None:
await ctx.defer() await ctx.defer()
@ -138,7 +138,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. Automatic invite active: {active}") await ctx.send(f"Settings applied. Automatic invite active: {active}")
@set_.subcommand(sub_cmd_name="notify", sub_cmd_description="Notify users of admin action?") @set_.subcommand(sub_cmd_name="notify", sub_cmd_description="Notify users of admin action?")
@slash_option(name="active", description="Notify?", opt_type=OptionTypes.BOOLEAN, required=True) @slash_option(name="active", description="Notify?", opt_type=OptionType.BOOLEAN, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _set_notify(self, ctx: InteractionContext, active: bool) -> None: async def _set_notify(self, ctx: InteractionContext, active: bool) -> None:
await ctx.defer() await ctx.defer()
@ -146,7 +146,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. Notifications active: {active}") await ctx.send(f"Settings applied. Notifications active: {active}")
@set_.subcommand(sub_cmd_name="log_ignore", sub_cmd_description="Ignore a channel for ActivityLog") @set_.subcommand(sub_cmd_name="log_ignore", sub_cmd_description="Ignore a channel for ActivityLog")
@slash_option(name="channel", description="Channel to ignore", opt_type=OptionTypes.CHANNEL, required=True) @slash_option(name="channel", description="Channel to ignore", opt_type=OptionType.CHANNEL, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _add_log_ignore(self, ctx: InteractionContext, channel: GuildText) -> None: async def _add_log_ignore(self, ctx: InteractionContext, channel: GuildText) -> None:
if not isinstance(channel, GuildText): if not isinstance(channel, GuildText):
@ -224,7 +224,7 @@ class SettingsCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to stop ignoring", description="Channel to stop ignoring",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@ -293,8 +293,8 @@ class SettingsCog(Extension):
async def _clear(self, ctx: InteractionContext) -> None: async def _clear(self, ctx: InteractionContext) -> None:
components = [ components = [
ActionRow( ActionRow(
Button(style=ButtonStyles.RED, emoji="✖️", custom_id=f"{ctx.guild.id}|set_clear|no"), Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"{ctx.guild.id}|set_clear|no"),
Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"{ctx.guild.id}|set_clear|yes"), Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"{ctx.guild.id}|set_clear|yes"),
) )
] ]
message = await ctx.send("***Are you sure?***", components=components) message = await ctx.send("***Are you sure?***", components=components)

View file

@ -7,11 +7,11 @@ from dateparser_data.settings import default_parsers
from interactions import Client, Extension, InteractionContext, Permissions from interactions import Client, Extension, InteractionContext, Permissions
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.role import Role from interactions.models.discord.role import Role
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
slash_command, slash_command,
slash_option, slash_option,
) )
@ -30,18 +30,18 @@ class TemproleCog(Extension):
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
@slash_command(name="temprole", description="Give a user a temporary role") @slash_command(name="temprole", description="Give a user a temporary role")
@slash_option(name="user", description="User to grant role", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to grant role", opt_type=OptionType.USER, required=True)
@slash_option(name="role", description="Role to grant", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Role to grant", opt_type=OptionType.ROLE, required=True)
@slash_option( @slash_option(
name="duration", name="duration",
description="Duration of temp role (i.e. 2 hours)", description="Duration of temp role (i.e. 2 hours)",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@slash_option( @slash_option(
name="reason", name="reason",
description="Reason for temporary role", description="Reason for temporary role",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_ROLES)) @check(admin_or_permissions(Permissions.MANAGE_ROLES))
@ -109,5 +109,5 @@ class TemproleCog(Extension):
fields=fields, fields=fields,
) )
embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=user.display_avatar.url) embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=user.display_avatar.url)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)

View file

@ -4,7 +4,7 @@ import logging
from random import randint from random import randint
from interactions import Client, Extension, InteractionContext from interactions import Client, Extension, InteractionContext
from interactions.models.discord.components import Button, ButtonStyles, spread_to_rows from interactions.models.discord.components import Button, ButtonStyle, spread_to_rows
from interactions.models.internal.application_commands import slash_command from interactions.models.internal.application_commands import slash_command
from interactions.models.internal.command import cooldown from interactions.models.internal.command import cooldown
from interactions.models.internal.cooldowns import Buckets from interactions.models.internal.cooldowns import Buckets
@ -19,7 +19,7 @@ def create_layout() -> list:
for i in range(3): for i in range(3):
label = "YES" if i == yes else "NO" label = "YES" if i == yes else "NO"
id = f"no_{i}" if not i == yes else "yes" id = f"no_{i}" if not i == yes else "yes"
color = ButtonStyles.GREEN if i == yes else ButtonStyles.RED color = ButtonStyle.GREEN if i == yes else ButtonStyle.RED
buttons.append( buttons.append(
Button( Button(
style=color, style=color,

View file

@ -7,7 +7,7 @@ from interactions.ext.paginators import Paginator
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
slash_command, slash_command,
slash_option, slash_option,
) )
@ -25,17 +25,17 @@ class WarningCog(ModcaseCog):
"""JARVIS WarningCog.""" """JARVIS WarningCog."""
@slash_command(name="warn", description="Warn a user") @slash_command(name="warn", description="Warn a user")
@slash_option(name="user", description="User to warn", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to warn", opt_type=OptionType.USER, required=True)
@slash_option( @slash_option(
name="reason", name="reason",
description="Reason for warning", description="Reason for warning",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@slash_option( @slash_option(
name="duration", name="duration",
description="Duration of warning in hours, default 24", description="Duration of warning in hours, default 24",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -67,11 +67,11 @@ class WarningCog(ModcaseCog):
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@slash_command(name="warnings", description="Get count of user warnings") @slash_command(name="warnings", description="Get count of user warnings")
@slash_option(name="user", description="User to view", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="User to view", opt_type=OptionType.USER, required=True)
@slash_option( @slash_option(
name="active", name="active",
description="View active only", description="View active only",
opt_type=OptionTypes.BOOLEAN, opt_type=OptionType.BOOLEAN,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))

View file

@ -11,7 +11,7 @@ from interactions.ext.prefixed_commands.command import prefixed_command
from interactions.ext.prefixed_commands.context import PrefixedContext from interactions.ext.prefixed_commands.context import PrefixedContext
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.file import File from interactions.models.discord.file import File
from rich.console import Console from rich.console import Console
@ -86,7 +86,7 @@ class BotutilCog(Extension):
) )
embed = build_embed(title="System Info", description="", fields=fields) embed = build_embed(title="System Info", description="", fields=fields)
embed.set_image(url=self.bot.user.avatar.url) embed.set_image(url=self.bot.user.avatar.url)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@prefixed_command(name="update") @prefixed_command(name="update")
@ -118,7 +118,7 @@ class BotutilCog(Extension):
self.logger.info("Updates applied") self.logger.info("Updates applied")
content = f"```ansi\n{capture.get()}\n```" content = f"```ansi\n{capture.get()}\n```"
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
if len(content) < 3000: if len(content) < 3000:
await ctx.reply(content, embeds=embed, components=components) await ctx.reply(content, embeds=embed, components=components)
else: else:
@ -131,7 +131,7 @@ class BotutilCog(Extension):
else: else:
embed = build_embed(title="Update Status", description="No changes applied", fields=[]) embed = build_embed(title="Update Status", description="No changes applied", fields=[])
embed.set_thumbnail(url="https://dev.zevaryx.com/git.png") embed.set_thumbnail(url="https://dev.zevaryx.com/git.png")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.reply(embeds=embed, components=components) await ctx.reply(embeds=embed, components=components)

View file

@ -11,10 +11,10 @@ from interactions import AutocompleteContext, Client, Extension, InteractionCont
from interactions.models.discord.channel import GuildChannel from interactions.models.discord.channel import GuildChannel
from interactions.models.discord.components import ActionRow, Button from interactions.models.discord.components import ActionRow, Button
from interactions.models.discord.embed import Embed, EmbedField from interactions.models.discord.embed import Embed, EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.modal import InputText, Modal, TextStyles from interactions.models.discord.modal import InputText, Modal, TextStyles
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -45,7 +45,7 @@ class RemindmeCog(Extension):
@slash_option( @slash_option(
name="private", name="private",
description="Send as DM?", description="Send as DM?",
opt_type=OptionTypes.BOOLEAN, opt_type=OptionType.BOOLEAN,
required=False, required=False,
) )
async def _remindme( async def _remindme(
@ -159,10 +159,10 @@ class RemindmeCog(Extension):
icon_url=ctx.author.display_avatar.url, icon_url=ctx.author.display_avatar.url,
) )
embed.set_thumbnail(url=ctx.author.display_avatar.url) embed.set_thumbnail(url=ctx.author.display_avatar.url)
delete_button = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") delete_button = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
components = [delete_button] components = [delete_button]
if not r.guild == ctx.author.id: if not r.guild == ctx.author.id:
copy_button = Button(style=ButtonStyles.GREEN, emoji="📋", custom_id=f"copy|rme|{r.id}") copy_button = Button(style=ButtonStyle.GREEN, emoji="📋", custom_id=f"copy|rme|{r.id}")
components.append(copy_button) components.append(copy_button)
private = private if private is not None else False private = private if private is not None else False
components = [ActionRow(*components)] components = [ActionRow(*components)]
@ -211,14 +211,14 @@ class RemindmeCog(Extension):
return return
embed = await self.get_reminders_embed(ctx, reminders) embed = await self.get_reminders_embed(ctx, reminders)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@reminders.subcommand(sub_cmd_name="delete", sub_cmd_description="Delete a reminder") @reminders.subcommand(sub_cmd_name="delete", sub_cmd_description="Delete a reminder")
@slash_option( @slash_option(
name="content", name="content",
description="Content of the reminder", description="Content of the reminder",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@ -244,7 +244,7 @@ class RemindmeCog(Extension):
) )
embed.set_thumbnail(url=ctx.author.display_avatar.url) embed.set_thumbnail(url=ctx.author.display_avatar.url)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
try: try:
await reminder.delete() await reminder.delete()
except Exception: except Exception:
@ -258,7 +258,7 @@ class RemindmeCog(Extension):
@slash_option( @slash_option(
name="content", name="content",
description="Content of the reminder", description="Content of the reminder",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@ -283,7 +283,7 @@ class RemindmeCog(Extension):
) )
embed.set_thumbnail(url=ctx.author.display_avatar.url) embed.set_thumbnail(url=ctx.author.display_avatar.url)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, ephemeral=reminder.private, components=components) await ctx.send(embeds=embed, ephemeral=reminder.private, components=components)
if reminder.remind_at <= datetime.now(tz=timezone.utc) and not reminder.active: if reminder.remind_at <= datetime.now(tz=timezone.utc) and not reminder.active:
try: try:

View file

@ -10,7 +10,7 @@ from asyncpraw.models.reddit.submission import Subreddit as Sub
from asyncprawcore.exceptions import Forbidden, NotFound, Redirect from asyncprawcore.exceptions import Forbidden, NotFound, Redirect
from interactions import Client, Extension, InteractionContext, Permissions from interactions import Client, Extension, InteractionContext, Permissions
from interactions.client.utils.misc_utils import get from interactions.client.utils.misc_utils import get
from interactions.models.discord.channel import ChannelTypes, GuildText from interactions.models.discord.channel import ChannelType, GuildText
from interactions.models.discord.components import ( from interactions.models.discord.components import (
ActionRow, ActionRow,
StringSelectMenu, StringSelectMenu,
@ -18,7 +18,7 @@ from interactions.models.discord.components import (
) )
from interactions.models.discord.embed import Embed, EmbedField from interactions.models.discord.embed import Embed, EmbedField
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
SlashCommandChoice, SlashCommandChoice,
slash_option, slash_option,
@ -143,14 +143,14 @@ class RedditCog(Extension):
@slash_option( @slash_option(
name="name", name="name",
description="Redditor name", description="Redditor name",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to post to", description="Channel to post to",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
channel_types=[ChannelTypes.GUILD_TEXT], channel_types=[ChannelType.GUILD_TEXT],
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -255,14 +255,14 @@ class RedditCog(Extension):
@slash_option( @slash_option(
name="name", name="name",
description="Subreddit display name", description="Subreddit display name",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to post to", description="Channel to post to",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
channel_types=[ChannelTypes.GUILD_TEXT], channel_types=[ChannelType.GUILD_TEXT],
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -371,7 +371,7 @@ class RedditCog(Extension):
await message.edit(components=components) await message.edit(components=components)
@reddit.subcommand(sub_cmd_name="hot", sub_cmd_description="Get the hot post of a subreddit") @reddit.subcommand(sub_cmd_name="hot", sub_cmd_description="Get the hot post of a subreddit")
@slash_option(name="name", description="Subreddit name", opt_type=OptionTypes.STRING, required=True) @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True)
async def _subreddit_hot(self, ctx: InteractionContext, name: str) -> None: async def _subreddit_hot(self, ctx: InteractionContext, name: str) -> None:
if not sub_name.match(name): if not sub_name.match(name):
await ctx.send("Invalid Subreddit name", ephemeral=True) await ctx.send("Invalid Subreddit name", ephemeral=True)
@ -404,11 +404,11 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds) await ctx.send(embeds=embeds)
@reddit.subcommand(sub_cmd_name="top", sub_cmd_description="Get the top post of a subreddit") @reddit.subcommand(sub_cmd_name="top", sub_cmd_description="Get the top post of a subreddit")
@slash_option(name="name", description="Subreddit name", opt_type=OptionTypes.STRING, required=True) @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True)
@slash_option( @slash_option(
name="time", name="time",
description="Top time", description="Top time",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
choices=[ choices=[
SlashCommandChoice(name="All", value="all"), SlashCommandChoice(name="All", value="all"),
@ -451,7 +451,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds) await ctx.send(embeds=embeds)
@reddit.subcommand(sub_cmd_name="random", sub_cmd_description="Get a random post of a subreddit") @reddit.subcommand(sub_cmd_name="random", sub_cmd_description="Get a random post of a subreddit")
@slash_option(name="name", description="Subreddit name", opt_type=OptionTypes.STRING, required=True) @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True)
async def _subreddit_random(self, ctx: InteractionContext, name: str) -> None: async def _subreddit_random(self, ctx: InteractionContext, name: str) -> None:
if not sub_name.match(name): if not sub_name.match(name):
await ctx.send("Invalid Subreddit name", ephemeral=True) await ctx.send("Invalid Subreddit name", ephemeral=True)
@ -484,7 +484,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds) await ctx.send(embeds=embeds)
@reddit.subcommand(sub_cmd_name="rising", sub_cmd_description="Get a rising post of a subreddit") @reddit.subcommand(sub_cmd_name="rising", sub_cmd_description="Get a rising post of a subreddit")
@slash_option(name="name", description="Subreddit name", opt_type=OptionTypes.STRING, required=True) @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True)
async def _subreddit_rising(self, ctx: InteractionContext, name: str) -> None: async def _subreddit_rising(self, ctx: InteractionContext, name: str) -> None:
if not sub_name.match(name): if not sub_name.match(name):
await ctx.send("Invalid Subreddit name", ephemeral=True) await ctx.send("Invalid Subreddit name", ephemeral=True)
@ -517,7 +517,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds) await ctx.send(embeds=embeds)
@reddit.subcommand(sub_cmd_name="post", sub_cmd_description="Get a specific submission") @reddit.subcommand(sub_cmd_name="post", sub_cmd_description="Get a specific submission")
@slash_option(name="sid", description="Submission ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="sid", description="Submission ID", opt_type=OptionType.STRING, required=True)
async def _reddit_post(self, ctx: InteractionContext, sid: str) -> None: async def _reddit_post(self, ctx: InteractionContext, sid: str) -> None:
await ctx.defer() await ctx.defer()
try: try:
@ -541,7 +541,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds) await ctx.send(embeds=embeds)
@reddit.subcommand(sub_cmd_name="dm_nsfw", sub_cmd_description="DM NSFW posts if channel isn't NSFW") @reddit.subcommand(sub_cmd_name="dm_nsfw", sub_cmd_description="DM NSFW posts if channel isn't NSFW")
@slash_option(name="dm", description="Send DM?", opt_type=OptionTypes.BOOLEAN, required=True) @slash_option(name="dm", description="Send DM?", opt_type=OptionType.BOOLEAN, required=True)
async def _reddit_dm(self, ctx: InteractionContext, dm: bool) -> None: async def _reddit_dm(self, ctx: InteractionContext, dm: bool) -> None:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw"))
if not setting: if not setting:

View file

@ -12,7 +12,7 @@ from interactions.models.discord.components import (
StringSelectOption, StringSelectOption,
) )
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -45,17 +45,17 @@ class TwitterCog(Extension):
sub_cmd_name="follow", sub_cmd_name="follow",
sub_cmd_description="Follow a Twitter acount", sub_cmd_description="Follow a Twitter acount",
) )
@slash_option(name="handle", description="Twitter account", opt_type=OptionTypes.STRING, required=True) @slash_option(name="handle", description="Twitter account", opt_type=OptionType.STRING, required=True)
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to post tweets to", description="Channel to post tweets to",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@slash_option( @slash_option(
name="retweets", name="retweets",
description="Mirror re-tweets?", description="Mirror re-tweets?",
opt_type=OptionTypes.BOOLEAN, opt_type=OptionType.BOOLEAN,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -171,7 +171,7 @@ class TwitterCog(Extension):
@slash_option( @slash_option(
name="retweets", name="retweets",
description="Mirror re-tweets?", description="Mirror re-tweets?",
opt_type=OptionTypes.BOOLEAN, opt_type=OptionType.BOOLEAN,
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))

View file

@ -9,19 +9,19 @@ from io import BytesIO
import numpy as np import numpy as np
from dateparser import parse from dateparser import parse
from interactions import Client, Extension, InteractionContext from interactions import Client, Extension, SlashContext
from interactions import __version__ as ipyv from interactions import __version__ as ipyv
from interactions.models.discord.channel import GuildCategory, GuildText, GuildVoice from interactions.models.discord.channel import GuildCategory, GuildText, GuildVoice
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.file import File from interactions.models.discord.file import File
from interactions.models.discord.guild import Guild from interactions.models.discord.guild import Guild
from interactions.models.discord.role import Role from interactions.models.discord.role import Role
from interactions.models.discord.user import User from interactions.models.discord.user import User
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
CommandTypes, CommandType,
OptionTypes, OptionType,
SlashCommand, SlashCommand,
SlashCommandChoice, SlashCommandChoice,
context_menu, context_menu,
@ -55,7 +55,7 @@ class UtilCog(Extension):
bot = SlashCommand(name="bot", description="Bot commands") bot = SlashCommand(name="bot", description="Bot commands")
@bot.subcommand(sub_cmd_name="sex", sub_cmd_description="Have sex with JARVIS") @bot.subcommand(sub_cmd_name="sex", sub_cmd_description="Have sex with JARVIS")
async def _sex(self, ctx: InteractionContext) -> None: async def _sex(self, ctx: SlashContext) -> None:
if ctx.author.id == 264072583987593217: if ctx.author.id == 264072583987593217:
await ctx.send("Oh fuck no, go fuck yourself") await ctx.send("Oh fuck no, go fuck yourself")
elif ctx.author.id == 840031256201003008: elif ctx.author.id == 840031256201003008:
@ -71,13 +71,15 @@ class UtilCog(Extension):
@bot.subcommand(sub_cmd_name="status", sub_cmd_description="Retrieve JARVIS status") @bot.subcommand(sub_cmd_name="status", sub_cmd_description="Retrieve JARVIS status")
@cooldown(bucket=Buckets.CHANNEL, rate=1, interval=30) @cooldown(bucket=Buckets.CHANNEL, rate=1, interval=30)
async def _status(self, ctx: InteractionContext) -> None: async def _status(self, ctx: SlashContext) -> None:
self.bot.logger.debug("Entered bot status")
title = "JARVIS Status" title = "JARVIS Status"
desc = ( desc = (
f"All systems online" f"All systems online"
f"\nConnected to **{len(self.bot.guilds)}** guilds" f"\nConnected to **{len(self.bot.guilds)}** guilds"
f"\nListening for **{len(self.bot.application_commands)}** commands" f"\nListening for **{len(self.bot.application_commands)}** commands"
) )
self.bot.logger.debug("Description made")
color = "#3498db" color = "#3498db"
fields = [] fields = []
uptime = int(self.bot.start_time.timestamp()) uptime = int(self.bot.start_time.timestamp())
@ -92,13 +94,14 @@ class UtilCog(Extension):
fields.append( fields.append(
EmbedField(name="interactions", value=f"[{ipyv}](https://interactionspy.readthedocs.io)", inline=True) EmbedField(name="interactions", value=f"[{ipyv}](https://interactionspy.readthedocs.io)", inline=True)
) )
self.bot.logger.debug("Getting repo information")
repo_url = f"https://git.zevaryx.com/stark-industries/jarvis/jarvis-bot/-/tree/{get_repo_hash()}" repo_url = f"https://git.zevaryx.com/stark-industries/jarvis/jarvis-bot/-/tree/{get_repo_hash()}"
fields.append(EmbedField(name="Git Hash", value=f"[{get_repo_hash()[:7]}]({repo_url})", inline=True)) fields.append(EmbedField(name="Git Hash", value=f"[{get_repo_hash()[:7]}]({repo_url})", inline=True))
fields.append(EmbedField(name="Online Since", value=f"<t:{uptime}:F>", inline=False)) fields.append(EmbedField(name="Online Since", value=f"<t:{uptime}:F>", inline=False))
num_domains = len(self.bot.phishing_domains) num_domains = len(self.bot.phishing_domains)
fields.append(EmbedField(name="Phishing Protection", value=f"Detecting {num_domains} phishing domains")) fields.append(EmbedField(name="Phishing Protection", value=f"Detecting {num_domains} phishing domains"))
embed = build_embed(title=title, description=desc, fields=fields, color=color) embed = build_embed(title=title, description=desc, fields=fields, color=color)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@bot.subcommand( @bot.subcommand(
@ -106,18 +109,18 @@ class UtilCog(Extension):
sub_cmd_description="Get the current logo", sub_cmd_description="Get the current logo",
) )
@cooldown(bucket=Buckets.CHANNEL, rate=1, interval=30) @cooldown(bucket=Buckets.CHANNEL, rate=1, interval=30)
async def _logo(self, ctx: InteractionContext) -> None: async def _logo(self, ctx: SlashContext) -> None:
with BytesIO() as image_bytes: with BytesIO() as image_bytes:
JARVIS_LOGO.save(image_bytes, "PNG") JARVIS_LOGO.save(image_bytes, "PNG")
image_bytes.seek(0) image_bytes.seek(0)
logo = File(image_bytes, file_name="logo.png") logo = File(image_bytes, file_name="logo.png")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(file=logo, components=components) await ctx.send(file=logo, components=components)
rc = SlashCommand(name="rc", description="Robot Camo emoji commands") rc = SlashCommand(name="rc", description="Robot Camo emoji commands")
@rc.subcommand(sub_cmd_name="hk", sub_cmd_description="Robot Camo HK416") @rc.subcommand(sub_cmd_name="hk", sub_cmd_description="Robot Camo HK416")
async def _rchk(self, ctx: InteractionContext) -> None: async def _rchk(self, ctx: SlashContext) -> None:
await ctx.send(content=hk, ephemeral=True) await ctx.send(content=hk, ephemeral=True)
@rc.subcommand( @rc.subcommand(
@ -127,10 +130,10 @@ class UtilCog(Extension):
@slash_option( @slash_option(
name="text", name="text",
description="Text to camo-ify", description="Text to camo-ify",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
async def _rcauto(self, ctx: InteractionContext, text: str) -> None: async def _rcauto(self, ctx: SlashContext, text: str) -> None:
to_send = "" to_send = ""
if len(text) == 1 and not re.match(r"^[A-Z0-9-()$@!?^'#. ]$", text.upper()): if len(text) == 1 and not re.match(r"^[A-Z0-9-()$@!?^'#. ]$", text.upper()):
await ctx.send("Please use ASCII characters.", ephemeral=True) await ctx.send("Please use ASCII characters.", ephemeral=True)
@ -148,7 +151,7 @@ class UtilCog(Extension):
else: else:
await ctx.send(to_send, ephemeral=True) await ctx.send(to_send, ephemeral=True)
async def _avatar(self, ctx: InteractionContext, user: User = None) -> None: async def _avatar(self, ctx: SlashContext, user: User = None) -> None:
if not user: if not user:
user = ctx.author user = ctx.author
@ -157,7 +160,7 @@ class UtilCog(Extension):
embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE") embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE")
embed.set_image(url=avatar) embed.set_image(url=avatar)
embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=avatar) embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=avatar)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@slash_command( @slash_command(
@ -167,10 +170,10 @@ class UtilCog(Extension):
@slash_option( @slash_option(
name="role", name="role",
description="Role to get info of", description="Role to get info of",
opt_type=OptionTypes.ROLE, opt_type=OptionType.ROLE,
required=True, required=True,
) )
async def _roleinfo(self, ctx: InteractionContext, role: Role) -> None: async def _roleinfo(self, ctx: SlashContext, role: Role) -> None:
fields = [ fields = [
EmbedField(name="ID", value=str(role.id), inline=True), EmbedField(name="ID", value=str(role.id), inline=True),
EmbedField(name="Name", value=role.mention, inline=True), EmbedField(name="Name", value=role.mention, inline=True),
@ -205,25 +208,25 @@ class UtilCog(Extension):
im.save(image_bytes, "PNG") im.save(image_bytes, "PNG")
image_bytes.seek(0) image_bytes.seek(0)
color_show = File(image_bytes, file_name="color_show.png") color_show = File(image_bytes, file_name="color_show.png")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, file=color_show, components=components) await ctx.send(embeds=embed, file=color_show, components=components)
@slash_command(name="avatar", description="Get a user avatar") @slash_command(name="avatar", description="Get a user avatar")
@slash_option( @slash_option(
name="user", name="user",
description="User to view avatar of", description="User to view avatar of",
opt_type=OptionTypes.USER, opt_type=OptionType.USER,
required=False, required=False,
) )
@cooldown(bucket=Buckets.USER, rate=1, interval=5) @cooldown(bucket=Buckets.USER, rate=1, interval=5)
async def _avatar_slash(self, ctx: InteractionContext, user: User = None) -> None: async def _avatar_slash(self, ctx: SlashContext, user: User = None) -> None:
await self._avatar(ctx, user) await self._avatar(ctx, user)
@context_menu(name="Avatar", context_type=CommandTypes.USER) @context_menu(name="Avatar", context_type=CommandType.USER)
async def _avatar_menu(self, ctx: InteractionContext) -> None: async def _avatar_menu(self, ctx: SlashContext) -> None:
await self._avatar(ctx, ctx.target) await self._avatar(ctx, ctx.target)
async def _userinfo(self, ctx: InteractionContext, user: User = None) -> None: async def _userinfo(self, ctx: SlashContext, user: User = None) -> None:
await ctx.defer() await ctx.defer()
if not user: if not user:
user = ctx.author user = ctx.author
@ -271,12 +274,12 @@ class UtilCog(Extension):
) )
embed.set_thumbnail(url=user.display_avatar.url) embed.set_thumbnail(url=user.display_avatar.url)
embed.set_footer(text=f"ID: {user.id}") embed.set_footer(text=f"ID: {user.id}")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@slash_command(name="lmgtfy", description="Let me Google that for you") @slash_command(name="lmgtfy", description="Let me Google that for you")
@slash_option(name="search", description="What to search", opt_type=OptionTypes.STRING, required=True) @slash_option(name="search", description="What to search", opt_type=OptionType.STRING, required=True)
async def _lmgtfy(self, ctx: InteractionContext, search: str) -> None: async def _lmgtfy(self, ctx: SlashContext, search: str) -> None:
url = "https://letmegooglethat.com/?q=" + urllib.parse.quote_plus(search) url = "https://letmegooglethat.com/?q=" + urllib.parse.quote_plus(search)
await ctx.send(url) await ctx.send(url)
@ -287,18 +290,18 @@ class UtilCog(Extension):
@slash_option( @slash_option(
name="user", name="user",
description="User to get info of", description="User to get info of",
opt_type=OptionTypes.USER, opt_type=OptionType.USER,
required=False, required=False,
) )
async def _userinfo_slsh(self, ctx: InteractionContext, user: User = None) -> None: async def _userinfo_slsh(self, ctx: SlashContext, user: User = None) -> None:
await self._userinfo(ctx, user) await self._userinfo(ctx, user)
@context_menu(name="User Info", context_type=CommandTypes.USER) @context_menu(name="User Info", context_type=CommandType.USER)
async def _userinfo_menu(self, ctx: InteractionContext) -> None: async def _userinfo_menu(self, ctx: SlashContext) -> None:
await self._userinfo(ctx, ctx.target) await self._userinfo(ctx, ctx.target)
@slash_command(name="serverinfo", description="Get server info") @slash_command(name="serverinfo", description="Get server info")
async def _server_info(self, ctx: InteractionContext) -> None: async def _server_info(self, ctx: SlashContext) -> None:
guild: Guild = ctx.guild guild: Guild = ctx.guild
owner = await guild.fetch_owner() owner = await guild.fetch_owner()
@ -332,7 +335,7 @@ class UtilCog(Extension):
embed.set_author(name=guild.name, icon_url=guild.icon.url) embed.set_author(name=guild.name, icon_url=guild.icon.url)
embed.set_thumbnail(url=guild.icon.url) embed.set_thumbnail(url=guild.icon.url)
embed.set_footer(text=f"ID: {guild.id} | Server Created") embed.set_footer(text=f"ID: {guild.id} | Server Created")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@slash_command( @slash_command(
@ -344,13 +347,13 @@ class UtilCog(Extension):
@slash_option( @slash_option(
name="length", name="length",
description="Password length (default 32)", description="Password length (default 32)",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
) )
@slash_option( @slash_option(
name="chars", name="chars",
description="Characters to include (default last option)", description="Characters to include (default last option)",
opt_type=OptionTypes.INTEGER, opt_type=OptionType.INTEGER,
required=False, required=False,
choices=[ choices=[
SlashCommandChoice(name="A-Za-z", value=0), SlashCommandChoice(name="A-Za-z", value=0),
@ -360,7 +363,7 @@ class UtilCog(Extension):
], ],
) )
@cooldown(bucket=Buckets.USER, rate=1, interval=15) @cooldown(bucket=Buckets.USER, rate=1, interval=15)
async def _pw_gen(self, ctx: InteractionContext, length: int = 32, chars: int = 3) -> None: async def _pw_gen(self, ctx: SlashContext, length: int = 32, chars: int = 3) -> None:
if length > 256: if length > 256:
await ctx.send("Please limit password to 256 characters", ephemeral=True) await ctx.send("Please limit password to 256 characters", ephemeral=True)
return return
@ -381,8 +384,8 @@ class UtilCog(Extension):
) )
@slash_command(name="pigpen", description="Encode a string into pigpen") @slash_command(name="pigpen", description="Encode a string into pigpen")
@slash_option(name="text", description="Text to encode", opt_type=OptionTypes.STRING, required=True) @slash_option(name="text", description="Text to encode", opt_type=OptionType.STRING, required=True)
async def _pigpen(self, ctx: InteractionContext, text: str) -> None: async def _pigpen(self, ctx: SlashContext, text: str) -> None:
outp = "`" outp = "`"
for c in text: for c in text:
c = c.lower() c = c.lower()
@ -397,9 +400,9 @@ class UtilCog(Extension):
await ctx.send(outp[:2000]) await ctx.send(outp[:2000])
@slash_command(name="timestamp", description="Convert a datetime or timestamp into it's counterpart") @slash_command(name="timestamp", description="Convert a datetime or timestamp into it's counterpart")
@slash_option(name="string", description="String to convert", opt_type=OptionTypes.STRING, required=True) @slash_option(name="string", description="String to convert", opt_type=OptionType.STRING, required=True)
@slash_option(name="private", description="Respond quietly?", opt_type=OptionTypes.BOOLEAN, required=False) @slash_option(name="private", description="Respond quietly?", opt_type=OptionType.BOOLEAN, required=False)
async def _timestamp(self, ctx: InteractionContext, string: str, private: bool = False) -> None: async def _timestamp(self, ctx: SlashContext, string: str, private: bool = False) -> None:
timestamp = parse(string) timestamp = parse(string)
if not timestamp: if not timestamp:
await ctx.send("Valid time not found, try again", ephemeral=True) await ctx.send("Valid time not found, try again", ephemeral=True)
@ -420,11 +423,11 @@ class UtilCog(Extension):
EmbedField(name="ISO8601", value=timestamp.isoformat()), EmbedField(name="ISO8601", value=timestamp.isoformat()),
] ]
embed = build_embed(title="Converted Time", description=f"`{string}`", fields=fields) embed = build_embed(title="Converted Time", description=f"`{string}`", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, ephemeral=private, components=components) await ctx.send(embeds=embed, ephemeral=private, components=components)
@bot.subcommand(sub_cmd_name="support", sub_cmd_description="Got issues?") @bot.subcommand(sub_cmd_name="support", sub_cmd_description="Got issues?")
async def _support(self, ctx: InteractionContext) -> None: async def _support(self, ctx: SlashContext) -> None:
await ctx.send( await ctx.send(
f""" f"""
Run into issues with {self.bot.user.mention}? Please report them here! Run into issues with {self.bot.user.mention}? Please report them here!
@ -436,7 +439,7 @@ We'll help as best we can with whatever issues you encounter.
) )
@bot.subcommand(sub_cmd_name="privacy_terms", sub_cmd_description="View Privacy and Terms of Use") @bot.subcommand(sub_cmd_name="privacy_terms", sub_cmd_description="View Privacy and Terms of Use")
async def _privacy_terms(self, ctx: InteractionContext) -> None: async def _privacy_terms(self, ctx: SlashContext) -> None:
await ctx.send( await ctx.send(
""" """
View the privacy statement here: https://s.zevs.me/jarvis-privacy View the privacy statement here: https://s.zevs.me/jarvis-privacy

View file

@ -6,9 +6,9 @@ from calculator import calculate
from interactions import AutocompleteContext, Client, Extension, InteractionContext from interactions import AutocompleteContext, Client, Extension, InteractionContext
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import Embed, EmbedField from interactions.models.discord.embed import Embed, EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
SlashCommandChoice, SlashCommandChoice,
slash_option, slash_option,
@ -76,13 +76,13 @@ class CalcCog(Extension):
calc = SlashCommand(name="calc", description="Calculate some things") calc = SlashCommand(name="calc", description="Calculate some things")
@calc.subcommand(sub_cmd_name="math", sub_cmd_description="Do a basic math calculation") @calc.subcommand(sub_cmd_name="math", sub_cmd_description="Do a basic math calculation")
@slash_option(name="expression", description="Expression to calculate", required=True, opt_type=OptionTypes.STRING) @slash_option(name="expression", description="Expression to calculate", required=True, opt_type=OptionType.STRING)
async def _calc_math(self, ctx: InteractionContext, expression: str) -> None: async def _calc_math(self, ctx: InteractionContext, expression: str) -> None:
if expression == "The answer to life, the universe, and everything": if expression == "The answer to life, the universe, and everything":
fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(42))) fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(42)))
embed = build_embed(title="Calculator", description=None, fields=fields) embed = build_embed(title="Calculator", description=None, fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
return return
try: try:
@ -97,18 +97,18 @@ class CalcCog(Extension):
fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(value))) fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(value)))
embed = build_embed(title="Calculator", description=None, fields=fields) embed = build_embed(title="Calculator", description=None, fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
convert = calc.group(name="convert", description="Conversion helpers") convert = calc.group(name="convert", description="Conversion helpers")
@convert.subcommand(sub_cmd_name="temperature", sub_cmd_description="Convert between temperatures") @convert.subcommand(sub_cmd_name="temperature", sub_cmd_description="Convert between temperatures")
@slash_option(name="value", description="Value to convert", required=True, opt_type=OptionTypes.NUMBER) @slash_option(name="value", description="Value to convert", required=True, opt_type=OptionType.NUMBER)
@slash_option( @slash_option(
name="from_unit", description="From unit", required=True, opt_type=OptionTypes.INTEGER, choices=TEMP_CHOICES name="from_unit", description="From unit", required=True, opt_type=OptionType.INTEGER, choices=TEMP_CHOICES
) )
@slash_option( @slash_option(
name="to_unit", description="To unit", required=True, opt_type=OptionTypes.INTEGER, choices=TEMP_CHOICES name="to_unit", description="To unit", required=True, opt_type=OptionType.INTEGER, choices=TEMP_CHOICES
) )
async def _calc_convert_temperature( async def _calc_convert_temperature(
self, ctx: InteractionContext, value: int, from_unit: int, to_unit: int self, ctx: InteractionContext, value: int, from_unit: int, to_unit: int
@ -139,23 +139,23 @@ class CalcCog(Extension):
description=f"°{TEMP_LOOKUP.get(from_unit)} -> °{TEMP_LOOKUP.get(to_unit)}", description=f"°{TEMP_LOOKUP.get(from_unit)} -> °{TEMP_LOOKUP.get(to_unit)}",
fields=fields, fields=fields,
) )
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@convert.subcommand(sub_cmd_name="currency", sub_cmd_description="Convert currency based on current rates") @convert.subcommand(sub_cmd_name="currency", sub_cmd_description="Convert currency based on current rates")
@slash_option(name="value", description="Value of starting currency", required=True, opt_type=OptionTypes.NUMBER) @slash_option(name="value", description="Value of starting currency", required=True, opt_type=OptionType.NUMBER)
@slash_option( @slash_option(
name="from_currency", name="from_currency",
description="Currency to convert from", description="Currency to convert from",
required=True, required=True,
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_currency", name="to_currency",
description="Currency to convert to", description="Currency to convert to",
required=True, required=True,
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
autocomplete=True, autocomplete=True,
) )
async def _calc_convert_currency( async def _calc_convert_currency(
@ -174,180 +174,180 @@ class CalcCog(Extension):
) )
embed = build_embed(title="Conversion", description=f"{from_currency} -> {to_currency}", fields=fields) embed = build_embed(title="Conversion", description=f"{from_currency} -> {to_currency}", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
async def _convert(self, ctx: InteractionContext, from_: str, to: str, value: int) -> Embed: async def _convert(self, ctx: InteractionContext, from_: str, to: str, value: int) -> Embed:
*_, which = ctx.invoked_name.split(" ") *_, which = ctx.invoke_target.split(" ")
which = getattr(units, which.capitalize(), None) which = getattr(units, which.capitalize(), None)
ratio = which.get_rate(from_, to) ratio = which.get_rate(from_, to)
converted = value / ratio converted = value / ratio
fields = (EmbedField(name=from_, value=f"{value:0.2f}"), EmbedField(name=to, value=f"{converted:0.2f}")) fields = (EmbedField(name=from_, value=f"{value:0.2f}"), EmbedField(name=to, value=f"{converted:0.2f}"))
embed = build_embed(title="Conversion", description=f"{from_} -> {to}", fields=fields) embed = build_embed(title="Conversion", description=f"{from_} -> {to}", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@convert.subcommand(sub_cmd_name="angle", sub_cmd_description="Convert angles") @convert.subcommand(sub_cmd_name="angle", sub_cmd_description="Convert angles")
@slash_option(name="value", description="Angle to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Angle to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_angle(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_angle(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="area", sub_cmd_description="Convert areas") @convert.subcommand(sub_cmd_name="area", sub_cmd_description="Convert areas")
@slash_option(name="value", description="Area to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Area to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_area(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_area(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="data", sub_cmd_description="Convert data sizes") @convert.subcommand(sub_cmd_name="data", sub_cmd_description="Convert data sizes")
@slash_option(name="value", description="Data size to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Data size to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_data(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_data(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="energy", sub_cmd_description="Convert energy") @convert.subcommand(sub_cmd_name="energy", sub_cmd_description="Convert energy")
@slash_option(name="value", description="Energy to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Energy to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_energy(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_energy(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="length", sub_cmd_description="Convert lengths") @convert.subcommand(sub_cmd_name="length", sub_cmd_description="Convert lengths")
@slash_option(name="value", description="Length to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Length to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_length(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_length(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="power", sub_cmd_description="Convert powers") @convert.subcommand(sub_cmd_name="power", sub_cmd_description="Convert powers")
@slash_option(name="value", description="Power to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Power to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_power(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_power(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="pressure", sub_cmd_description="Convert pressures") @convert.subcommand(sub_cmd_name="pressure", sub_cmd_description="Convert pressures")
@slash_option(name="value", description="Pressure to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Pressure to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_pressure(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_pressure(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="speed", sub_cmd_description="Convert speeds") @convert.subcommand(sub_cmd_name="speed", sub_cmd_description="Convert speeds")
@slash_option(name="value", description="Speed to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Speed to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_speed(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_speed(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="time", sub_cmd_description="Convert times") @convert.subcommand(sub_cmd_name="time", sub_cmd_description="Convert times")
@slash_option(name="value", description="Time to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Time to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_time(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_time(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="volume", sub_cmd_description="Convert volumes") @convert.subcommand(sub_cmd_name="volume", sub_cmd_description="Convert volumes")
@slash_option(name="value", description="Volume to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Volume to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_volume(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_volume(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="weight", sub_cmd_description="Convert weights") @convert.subcommand(sub_cmd_name="weight", sub_cmd_description="Convert weights")
@slash_option(name="value", description="Weight to convert", opt_type=OptionTypes.NUMBER, required=True) @slash_option(name="value", description="Weight to convert", opt_type=OptionType.NUMBER, required=True)
@slash_option( @slash_option(
name="from_unit", name="from_unit",
description="Units to convert from", description="Units to convert from",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@slash_option( @slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True
) )
async def _calc_convert_weight(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: async def _calc_convert_weight(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value) await self._convert(ctx, from_unit, to_unit, value)
@ -370,12 +370,10 @@ class CalcCog(Extension):
@_calc_convert_time.autocomplete("from_unit") @_calc_convert_time.autocomplete("from_unit")
@_calc_convert_volume.autocomplete("from_unit") @_calc_convert_volume.autocomplete("from_unit")
@_calc_convert_weight.autocomplete("from_unit") @_calc_convert_weight.autocomplete("from_unit")
async def _autocomplete_from_unit( async def _autocomplete_from_unit(self, ctx: AutocompleteContext) -> None:
self, ctx: AutocompleteContext, from_unit: str, to_unit: str = None, value: int = 0 *_, which = ctx.invoke_target.split(" ")
) -> None:
*_, which = ctx.invoked_name.split(" ")
which = getattr(units, which.capitalize(), None) which = getattr(units, which.capitalize(), None)
await ctx.send(choices=self._unit_autocomplete(which, from_unit)) await ctx.send(choices=self._unit_autocomplete(which, ctx.input_text))
@_calc_convert_angle.autocomplete("to_unit") @_calc_convert_angle.autocomplete("to_unit")
@_calc_convert_area.autocomplete("to_unit") @_calc_convert_area.autocomplete("to_unit")
@ -388,12 +386,10 @@ class CalcCog(Extension):
@_calc_convert_time.autocomplete("to_unit") @_calc_convert_time.autocomplete("to_unit")
@_calc_convert_volume.autocomplete("to_unit") @_calc_convert_volume.autocomplete("to_unit")
@_calc_convert_weight.autocomplete("to_unit") @_calc_convert_weight.autocomplete("to_unit")
async def _autocomplete_to_unit( async def _autocomplete_to_unit(self, ctx: AutocompleteContext) -> None:
self, ctx: AutocompleteContext, from_unit: str, to_unit: str = None, value: int = 0 *_, which = ctx.invoke_target.split(" ")
) -> None:
*_, which = ctx.invoked_name.split(" ")
which = getattr(units, which.capitalize(), None) which = getattr(units, which.capitalize(), None)
await ctx.send(choices=self._unit_autocomplete(which, to_unit)) await ctx.send(choices=self._unit_autocomplete(which, ctx.input_text))
def _currency_autocomplete(self, currency: str) -> list[dict[str, str]]: def _currency_autocomplete(self, currency: str) -> list[dict[str, str]]:
results = process.extract(currency, CURRENCIES, limit=25) results = process.extract(currency, CURRENCIES, limit=25)
@ -402,16 +398,12 @@ class CalcCog(Extension):
return [{"name": r[0], "value": r[0]} for r in results] return [{"name": r[0], "value": r[0]} for r in results]
@_calc_convert_currency.autocomplete("from_currency") @_calc_convert_currency.autocomplete("from_currency")
async def _autocomplete_from_currency( async def _autocomplete_from_currency(self, ctx: AutocompleteContext) -> None:
self, ctx: AutocompleteContext, from_currency: str = None, to_currency: str = None, value: int = 0 await ctx.send(choices=self._currency_autocomplete(ctx.input_text))
) -> None:
await ctx.send(choices=self._currency_autocomplete(from_currency))
@_calc_convert_currency.autocomplete("to_currency") @_calc_convert_currency.autocomplete("to_currency")
async def _autocomplete_to_currency( async def _autocomplete_to_currency(self, ctx: AutocompleteContext) -> None:
self, ctx: AutocompleteContext, from_currency: str = None, to_currency: str = None, value: int = 0 await ctx.send(choices=self._currency_autocomplete(ctx.input_text))
) -> None:
await ctx.send(choices=self._currency_autocomplete(to_currency))
def setup(bot: Client) -> None: def setup(bot: Client) -> None:

View file

@ -15,11 +15,11 @@ from bson import ObjectId
from interactions import Client, Extension, InteractionContext from interactions import Client, Extension, InteractionContext
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.file import File from interactions.models.discord.file import File
from interactions.models.discord.message import Attachment from interactions.models.discord.message import Attachment
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
SlashCommandChoice, SlashCommandChoice,
slash_option, slash_option,
@ -64,17 +64,17 @@ class DevCog(Extension):
@slash_option( @slash_option(
name="method", name="method",
description="Hash method", description="Hash method",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in supported_hashes], choices=[SlashCommandChoice(name=x, value=x) for x in supported_hashes],
) )
@slash_option( @slash_option(
name="data", name="data",
description="Data to hash", description="Data to hash",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
) )
@slash_option(name="attach", description="File to hash", opt_type=OptionTypes.ATTACHMENT, required=False) @slash_option(name="attach", description="File to hash", opt_type=OptionType.ATTACHMENT, required=False)
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)
async def _hash(self, ctx: InteractionContext, method: str, data: str = None, attach: Attachment = None) -> None: async def _hash(self, ctx: InteractionContext, method: str, data: str = None, attach: Attachment = None) -> None:
if not data and not attach: if not data and not attach:
@ -117,21 +117,21 @@ class DevCog(Extension):
] ]
embed = build_embed(title=title, description=description, fields=fields) embed = build_embed(title=title, description=description, fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@dev.subcommand(sub_cmd_name="uuid", sub_cmd_description="Generate a UUID") @dev.subcommand(sub_cmd_name="uuid", sub_cmd_description="Generate a UUID")
@slash_option( @slash_option(
name="version", name="version",
description="UUID version", description="UUID version",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in ["3", "4", "5"]], choices=[SlashCommandChoice(name=x, value=x) for x in ["3", "4", "5"]],
) )
@slash_option( @slash_option(
name="data", name="data",
description="Data for UUID version 3,5", description="Data for UUID version 3,5",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
) )
async def _uuid(self, ctx: InteractionContext, version: str, data: str = None) -> None: async def _uuid(self, ctx: InteractionContext, version: str, data: str = None) -> None:
@ -173,7 +173,7 @@ class DevCog(Extension):
sub_cmd_name="uuid2ulid", sub_cmd_name="uuid2ulid",
sub_cmd_description="Convert a UUID to a ULID", sub_cmd_description="Convert a UUID to a ULID",
) )
@slash_option(name="uuid", description="UUID to convert", opt_type=OptionTypes.STRING, required=True) @slash_option(name="uuid", description="UUID to convert", opt_type=OptionType.STRING, required=True)
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)
async def _uuid2ulid(self, ctx: InteractionContext, uuid: str) -> None: async def _uuid2ulid(self, ctx: InteractionContext, uuid: str) -> None:
if UUID_VERIFY.match(uuid): if UUID_VERIFY.match(uuid):
@ -186,7 +186,7 @@ class DevCog(Extension):
sub_cmd_name="ulid2uuid", sub_cmd_name="ulid2uuid",
sub_cmd_description="Convert a ULID to a UUID", sub_cmd_description="Convert a ULID to a UUID",
) )
@slash_option(name="ulid", description="ULID to convert", opt_type=OptionTypes.STRING, required=True) @slash_option(name="ulid", description="ULID to convert", opt_type=OptionType.STRING, required=True)
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)
async def _ulid2uuid(self, ctx: InteractionContext, ulid: str) -> None: async def _ulid2uuid(self, ctx: InteractionContext, ulid: str) -> None:
if ULID_VERIFY.match(ulid): if ULID_VERIFY.match(ulid):
@ -201,14 +201,14 @@ class DevCog(Extension):
@slash_option( @slash_option(
name="method", name="method",
description="Encode method", description="Encode method",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods], choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods],
) )
@slash_option( @slash_option(
name="data", name="data",
description="Data to encode", description="Data to encode",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
async def _encode(self, ctx: InteractionContext, method: str, data: str) -> None: async def _encode(self, ctx: InteractionContext, method: str, data: str) -> None:
@ -230,21 +230,21 @@ class DevCog(Extension):
EmbedField(name=mstr, value=f"`{encoded}`", inline=False), EmbedField(name=mstr, value=f"`{encoded}`", inline=False),
] ]
embed = build_embed(title="Encoded Data", description="", fields=fields) embed = build_embed(title="Encoded Data", description="", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@dev.subcommand(sub_cmd_name="decode", sub_cmd_description="Decode some data") @dev.subcommand(sub_cmd_name="decode", sub_cmd_description="Decode some data")
@slash_option( @slash_option(
name="method", name="method",
description="Decode method", description="Decode method",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods], choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods],
) )
@slash_option( @slash_option(
name="data", name="data",
description="Data to decode", description="Data to decode",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
async def _decode(self, ctx: InteractionContext, method: str, data: str) -> None: async def _decode(self, ctx: InteractionContext, method: str, data: str) -> None:
@ -266,7 +266,7 @@ class DevCog(Extension):
EmbedField(name=mstr, value=f"`{decoded}`", inline=False), EmbedField(name=mstr, value=f"`{decoded}`", inline=False),
] ]
embed = build_embed(title="Decoded Data", description="", fields=fields) embed = build_embed(title="Decoded Data", description="", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@dev.subcommand(sub_cmd_name="cloc", sub_cmd_description="Get JARVIS lines of code") @dev.subcommand(sub_cmd_name="cloc", sub_cmd_description="Get JARVIS lines of code")

View file

@ -9,11 +9,11 @@ import numpy as np
from interactions import Client, Extension, InteractionContext from interactions import Client, Extension, InteractionContext
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.file import File from interactions.models.discord.file import File
from interactions.models.discord.message import Attachment from interactions.models.discord.message import Attachment
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -46,19 +46,19 @@ class ImageCog(Extension):
@slash_option( @slash_option(
name="target", name="target",
description="Target size, i.e. 200KB", description="Target size, i.e. 200KB",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@slash_option( @slash_option(
name="attachment", name="attachment",
description="Image to resize", description="Image to resize",
opt_type=OptionTypes.ATTACHMENT, opt_type=OptionType.ATTACHMENT,
required=False, required=False,
) )
@slash_option( @slash_option(
name="url", name="url",
description="URL to download and resize", description="URL to download and resize",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
) )
async def _resize( async def _resize(
@ -149,7 +149,7 @@ class ImageCog(Extension):
] ]
embed = build_embed(title=filename, description="", fields=fields) embed = build_embed(title=filename, description="", fields=fields)
embed.set_image(url="attachment://resized.png") embed.set_image(url="attachment://resized.png")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, file=File(file=bufio, file_name="resized.png"), components=components) await ctx.send(embeds=embed, file=File(file=bufio, file_name="resized.png"), components=components)

View file

@ -11,11 +11,11 @@ from interactions.models.discord.components import (
StringSelectMenu, StringSelectMenu,
StringSelectOption, StringSelectOption,
) )
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.message import Message from interactions.models.discord.message import Message
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
CommandTypes, CommandType,
OptionTypes, OptionType,
SlashCommand, SlashCommand,
context_menu, context_menu,
slash_option, slash_option,
@ -75,7 +75,7 @@ class PinboardCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Pinboard channel", description="Pinboard channel",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -111,7 +111,7 @@ class PinboardCog(Extension):
@slash_option( @slash_option(
name="channel", name="channel",
description="Pinboard channel", description="Pinboard channel",
opt_type=OptionTypes.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -233,7 +233,7 @@ class PinboardCog(Extension):
embed.set_footer(text=ctx.guild.name + " | " + channel.name) embed.set_footer(text=ctx.guild.name + " | " + channel.name)
if image_url: if image_url:
embed.set_image(url=image_url) embed.set_image(url=image_url)
star_components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") star_components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
star = await starboard.send(embeds=embed, components=star_components) star = await starboard.send(embeds=embed, components=star_components)
await Star( await Star(
@ -254,7 +254,7 @@ class PinboardCog(Extension):
components=components, components=components,
) )
@context_menu(name="Pin Message", context_type=CommandTypes.MESSAGE) @context_menu(name="Pin Message", context_type=CommandType.MESSAGE)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _star_message(self, ctx: InteractionContext) -> None: async def _star_message(self, ctx: InteractionContext) -> None:
await self._star_add(ctx, message=str(ctx.target_id)) await self._star_add(ctx, message=str(ctx.target_id))

View file

@ -19,10 +19,10 @@ from interactions.models.discord.components import (
StringSelectOption, StringSelectOption,
) )
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles from interactions.models.discord.enums import ButtonStyle
from interactions.models.discord.role import Role from interactions.models.discord.role import Role
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -53,13 +53,18 @@ class RolegiverCog(Extension):
if not guild: if not guild:
await rolegiver.delete() await rolegiver.delete()
continue continue
role = await guild.fetch_role(rolegiver.role) roles = []
if not role: for role in rolegiver.roles:
await rolegiver.delete() role = await guild.fetch_role(role)
if role:
roles.append(role.id)
else:
continue continue
if guild.id not in self.cache: if guild.id not in self.cache:
self.cache[guild.id] = {} self.cache[guild.id] = {}
self.cache[guild.id][role.name] = role.id self.cache[guild.id][role.name] = role.id
rolegiver.roles = roles
await rolegiver.commit()
rolegiver = SlashCommand(name="rolegiver", description="Allow users to choose their own roles") rolegiver = SlashCommand(name="rolegiver", description="Allow users to choose their own roles")
@ -67,7 +72,7 @@ class RolegiverCog(Extension):
sub_cmd_name="add", sub_cmd_name="add",
sub_cmd_description="Add a role to rolegiver", sub_cmd_description="Add a role to rolegiver",
) )
@slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Role to add", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None: async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None:
if role.id == ctx.guild.id: if role.id == ctx.guild.id:
@ -120,7 +125,7 @@ class RolegiverCog(Extension):
embed.set_thumbnail(url=ctx.guild.icon.url) embed.set_thumbnail(url=ctx.guild.icon.url)
embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
if ctx.guild.id not in self.cache: if ctx.guild.id not in self.cache:
@ -131,7 +136,7 @@ class RolegiverCog(Extension):
@slash_option( @slash_option(
name="role", name="role",
description="Name of role to add", description="Name of role to add",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@ -212,7 +217,7 @@ class RolegiverCog(Extension):
embed.set_thumbnail(url=ctx.guild.icon.url) embed.set_thumbnail(url=ctx.guild.icon.url)
embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}")
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@rolegiver.subcommand(sub_cmd_name="get", sub_cmd_description="Get a role") @rolegiver.subcommand(sub_cmd_name="get", sub_cmd_description="Get a role")

View file

@ -7,10 +7,10 @@ from typing import Dict, List
from interactions import AutocompleteContext, Client, Extension, InteractionContext from interactions import AutocompleteContext, Client, Extension, InteractionContext
from interactions.models.discord.components import Button from interactions.models.discord.components import Button
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.enums import ButtonStyles, Permissions from interactions.models.discord.enums import ButtonStyle, Permissions
from interactions.models.discord.modal import InputText, Modal, TextStyles from interactions.models.discord.modal import InputText, Modal, TextStyles
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -39,7 +39,7 @@ class TagCog(Extension):
name="name", name="name",
description="Tag to get", description="Tag to get",
autocomplete=True, autocomplete=True,
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
async def _get(self, ctx: InteractionContext, name: str) -> None: async def _get(self, ctx: InteractionContext, name: str) -> None:
@ -125,7 +125,7 @@ class TagCog(Extension):
icon_url=ctx.author.display_avatar.url, icon_url=ctx.author.display_avatar.url,
) )
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await response.send(embeds=embed, components=components) await response.send(embeds=embed, components=components)
if ctx.guild.id not in self.cache: if ctx.guild.id not in self.cache:
@ -136,7 +136,7 @@ class TagCog(Extension):
@slash_option( @slash_option(
name="name", name="name",
description="Tag name", description="Tag name",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
autocomplete=True, autocomplete=True,
required=True, required=True,
) )
@ -225,7 +225,7 @@ class TagCog(Extension):
name=ctx.author.username + "#" + ctx.author.discriminator, name=ctx.author.username + "#" + ctx.author.discriminator,
icon_url=ctx.author.display_avatar.url, icon_url=ctx.author.display_avatar.url,
) )
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await response.send(embeds=embed, components=components) await response.send(embeds=embed, components=components)
if tag.name not in self.cache[ctx.guild.id]: if tag.name not in self.cache[ctx.guild.id]:
self.cache[ctx.guild.id].remove(old_name) self.cache[ctx.guild.id].remove(old_name)
@ -235,7 +235,7 @@ class TagCog(Extension):
@slash_option( @slash_option(
name="name", name="name",
description="Tag name", description="Tag name",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@ -259,7 +259,7 @@ class TagCog(Extension):
@slash_option( @slash_option(
name="name", name="name",
description="Tag name", description="Tag name",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
autocomplete=True, autocomplete=True,
) )
@ -302,7 +302,7 @@ class TagCog(Extension):
name=f"{username}#{discrim}" if username else "Unknown User", name=f"{username}#{discrim}" if username else "Unknown User",
icon_url=url, icon_url=url,
) )
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@tag.subcommand(sub_cmd_name="list", sub_cmd_description="List tag names") @tag.subcommand(sub_cmd_name="list", sub_cmd_description="List tag names")
@ -310,7 +310,7 @@ class TagCog(Extension):
tags = await Tag.find(q(guild=ctx.guild.id)).to_list(None) tags = await Tag.find(q(guild=ctx.guild.id)).to_list(None)
names = "\n".join(f"`{t.name}`" for t in tags) names = "\n".join(f"`{t.name}`" for t in tags)
embed = build_embed(title="All Tags", description=names, fields=[]) embed = build_embed(title="All Tags", description=names, fields=[])
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@_get.autocomplete("name") @_get.autocomplete("name")

View file

@ -5,11 +5,11 @@ import re
import aiohttp import aiohttp
from interactions import Client, Extension, InteractionContext from interactions import Client, Extension, InteractionContext
from interactions.ext.paginators import Paginator from interactions.ext.paginators import Paginator
from interactions.models.discord.components import ActionRow, Button, ButtonStyles from interactions.models.discord.components import ActionRow, Button, ButtonStyle
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.user import Member, User from interactions.models.discord.user import Member, User
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -46,14 +46,14 @@ class CTCCog(Extension):
@ctc2.subcommand(sub_cmd_name="about") @ctc2.subcommand(sub_cmd_name="about")
@cooldown(bucket=Buckets.USER, rate=1, interval=30) @cooldown(bucket=Buckets.USER, rate=1, interval=30)
async def _about(self, ctx: InteractionContext) -> None: async def _about(self, ctx: InteractionContext) -> None:
components = [ActionRow(Button(style=ButtonStyles.URL, url="https://completethecode.com", label="More Info"))] components = [ActionRow(Button(style=ButtonStyle.URL, url="https://completethecode.com", label="More Info"))]
await ctx.send("See https://completethecode.com for more information", components=components) await ctx.send("See https://completethecode.com for more information", components=components)
@ctc2.subcommand( @ctc2.subcommand(
sub_cmd_name="pw", sub_cmd_name="pw",
sub_cmd_description="Guess a password for https://completethecodetwo.cards", sub_cmd_description="Guess a password for https://completethecodetwo.cards",
) )
@slash_option(name="guess", description="Guess a password", opt_type=OptionTypes.STRING, required=True) @slash_option(name="guess", description="Guess a password", opt_type=OptionType.STRING, required=True)
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)
async def _pw(self, ctx: InteractionContext, guess: str) -> None: async def _pw(self, ctx: InteractionContext, guess: str) -> None:
if len(guess) > 800: if len(guess) > 800:

View file

@ -9,7 +9,7 @@ from interactions import Client, Extension, InteractionContext
from interactions.client.utils import find from interactions.client.utils import find
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
@ -204,7 +204,7 @@ class DbrandCog(Extension):
@slash_option( @slash_option(
name="search", name="search",
description="Country search query (2 character code, country name, flag emoji)", description="Country search query (2 character code, country name, flag emoji)",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=True, required=True,
) )
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)

View file

@ -10,7 +10,7 @@ from interactions.models.discord.embed import Embed, EmbedField
from interactions.models.discord.modal import InputText, Modal, TextStyles from interactions.models.discord.modal import InputText, Modal, TextStyles
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from interactions.models.internal.application_commands import ( from interactions.models.internal.application_commands import (
OptionTypes, OptionType,
SlashCommand, SlashCommand,
SlashCommandChoice, SlashCommandChoice,
slash_command, slash_command,
@ -40,7 +40,7 @@ class GitlabCog(Extension):
sub_cmd_name="issue", sub_cmd_name="issue",
sub_cmd_description="Get an issue from GitLab", sub_cmd_description="Get an issue from GitLab",
) )
@slash_option(name="id", description="Issue ID", opt_type=OptionTypes.INTEGER, required=True) @slash_option(name="id", description="Issue ID", opt_type=OptionType.INTEGER, required=True)
async def _issue(self, ctx: InteractionContext, id: int) -> None: async def _issue(self, ctx: InteractionContext, id: int) -> None:
try: try:
issue = self.project.issues.get(int(id)) issue = self.project.issues.get(int(id))
@ -102,7 +102,7 @@ class GitlabCog(Extension):
sub_cmd_name="milestone", sub_cmd_name="milestone",
sub_cmd_description="Get a milestone from GitLab", sub_cmd_description="Get a milestone from GitLab",
) )
@slash_option(name="id", description="Milestone ID", opt_type=OptionTypes.INTEGER, required=True) @slash_option(name="id", description="Milestone ID", opt_type=OptionType.INTEGER, required=True)
async def _milestone(self, ctx: InteractionContext, id: int) -> None: async def _milestone(self, ctx: InteractionContext, id: int) -> None:
try: try:
milestone = self.project.milestones.get(int(id)) milestone = self.project.milestones.get(int(id))
@ -150,7 +150,7 @@ class GitlabCog(Extension):
sub_cmd_name="mr", sub_cmd_name="mr",
sub_cmd_description="Get a merge request from GitLab", sub_cmd_description="Get a merge request from GitLab",
) )
@slash_option(name="id", description="Merge Request ID", opt_type=OptionTypes.INTEGER, required=True) @slash_option(name="id", description="Merge Request ID", opt_type=OptionType.INTEGER, required=True)
async def _mergerequest(self, ctx: InteractionContext, id: int) -> None: async def _mergerequest(self, ctx: InteractionContext, id: int) -> None:
try: try:
mr = self.project.mergerequests.get(int(id)) mr = self.project.mergerequests.get(int(id))
@ -251,7 +251,7 @@ class GitlabCog(Extension):
@slash_option( @slash_option(
name="state", name="state",
description="State of issues to get", description="State of issues to get",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
choices=[ choices=[
SlashCommandChoice(name="Open", value="opened"), SlashCommandChoice(name="Open", value="opened"),
@ -305,7 +305,7 @@ class GitlabCog(Extension):
@slash_option( @slash_option(
name="state", name="state",
description="State of merge requests to get", description="State of merge requests to get",
opt_type=OptionTypes.STRING, opt_type=OptionType.STRING,
required=False, required=False,
choices=[ choices=[
SlashCommandChoice(name="Open", value="opened"), SlashCommandChoice(name="Open", value="opened"),
@ -391,7 +391,7 @@ class GitlabCog(Extension):
@slash_option( @slash_option(
name="user", name="user",
description="Credit someone else for this issue", description="Credit someone else for this issue",
opt_type=OptionTypes.USER, opt_type=OptionType.USER,
required=False, required=False,
) )
async def _open_issue(self, ctx: InteractionContext, user: Member = None) -> None: async def _open_issue(self, ctx: InteractionContext, user: Member = None) -> None:

View file

@ -1,14 +1,5 @@
"""JARVIS Prometheus extra tracking.""" from statipy.db import GuildMetadata
from prometheus_client import Counter, Info
malicious_tracker = Counter(
"jarvis_malicious_blocked",
"Amount of malicious messages blocked",
labelnames=["guild_id", "guild_name"],
)
warnings_tracker = Counter( class WarningMetadata(GuildMetadata):
"jarvis_warnings", "Amount of warnings given out", labelnames=["guild_id", "guild_name"] type: str
)
jarvis_info = Info("jarvis", "Jarvis version")

View file

@ -3,13 +3,14 @@ import logging
from datetime import timedelta from datetime import timedelta
from interactions import Client, Extension, InteractionContext from interactions import Client, Extension, InteractionContext
from interactions.models.discord.components import ActionRow, Button, ButtonStyles from interactions.models.discord.components import ActionRow, Button, ButtonStyle
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from jarvis_core.db import q from jarvis_core.db import q
from jarvis_core.db.models import Action, Ban, Kick, Modlog, Mute, Setting, Warning from jarvis_core.db.models import Action, Ban, Kick, Modlog, Mute, Setting, Warning
from statipy.db import Stat
from jarvis.tracking import warnings_tracker from jarvis.tracking import WarningMetadata
from jarvis.utils import build_embed from jarvis.utils import build_embed
MODLOG_LOOKUP = {"Ban": Ban, "Kick": Kick, "Mute": Mute, "Warning": Warning} MODLOG_LOOKUP = {"Ban": Ban, "Kick": Kick, "Mute": Mute, "Warning": Warning}
@ -41,8 +42,16 @@ class ModcaseCog(Extension):
if name in MODLOG_LOOKUP and ctx.invoke_target not in IGNORE_COMMANDS[name]: if name in MODLOG_LOOKUP and ctx.invoke_target not in IGNORE_COMMANDS[name]:
if name == "Warning": if name == "Warning":
tracker = warnings_tracker.labels(guild_id=ctx.guild.id, guild_name=ctx.guild.name) md = WarningMetadata(
tracker.inc() client_id=self.user.id,
client_name=self.client_name,
name="warning",
type="manual",
guild_id=message.guild.id,
guild_name=message.guild.name,
value=1,
)
await Stat(meta=md).insert()
user = kwargs.pop("user", None) user = kwargs.pop("user", None)
if not user and not ctx.target_id: if not user and not ctx.target_id:
self.logger.warning("Admin action %s missing user, exiting", name) self.logger.warning("Admin action %s missing user, exiting", name)
@ -141,8 +150,8 @@ class ModcaseCog(Extension):
embed.set_author(name=user.username + "#" + user.discriminator, icon_url=avatar_url) embed.set_author(name=user.username + "#" + user.discriminator, icon_url=avatar_url)
components = [ components = [
ActionRow( ActionRow(
Button(style=ButtonStyles.RED, emoji="✖️", custom_id="modcase|no"), Button(style=ButtonStyle.RED, emoji="✖️", custom_id="modcase|no"),
Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id="modcase|yes"), Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id="modcase|yes"),
) )
] ]
message = await channel.send(embeds=embed, components=components) message = await channel.send(embeds=embed, components=components)

1249
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -27,9 +27,10 @@ nest-asyncio = "^1.5.5"
thefuzz = {extras = ["speedup"], git = "https://github.com/zevaryx/thefuzz.git", rev = "master"} # Forked thefuzz = {extras = ["speedup"], git = "https://github.com/zevaryx/thefuzz.git", rev = "master"} # Forked
beautifulsoup4 = "^4.11.1" beautifulsoup4 = "^4.11.1"
calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"} # Mine calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"} # Mine
nafftrack = {git = "https://github.com/zevaryx/nafftrack.git"} # Contributed
redis = "^4.4.0" redis = "^4.4.0"
interactions = {git = "https://github.com/interactions-py/interactions.py", rev = "5.x"} interactions = {git = "https://github.com/interactions-py/interactions.py", rev = "5.x"}
statipy = {git = "https://github.com/zevaryx/statipy", rev = "main"}
beanie = "^1.17.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = {version = "^22.3.0", allow-prereleases = true} black = {version = "^22.3.0", allow-prereleases = true}