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
import jurigged
from statipy.db import init_db
from interactions import Intents
from jarvis_core.db import connect
from jarvis_core.log import get_logger
@ -65,12 +66,14 @@ async def run() -> None:
logger.addHandler(file_handler)
# 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_host = redis_config.pop("host")
redis = await aioredis.from_url(redis_host, decode_responses=True, **redis_config)
await init_db(**jconfig.mongo["connect"])
jarvis = Jarvis(
intents=intents,
sync_interactions=jconfig.sync,
@ -99,8 +102,9 @@ async def run() -> None:
for extension in get_extensions(cogs_path):
jarvis.load_extension(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
logger.debug("Running JARVIS")

View file

@ -6,6 +6,7 @@ from interactions import Client
from interactions.ext.prefixed_commands.context import PrefixedContext
from interactions.models.internal.context import BaseContext, InteractionContext
from jarvis_core.util.ansi import Fore, Format, fmt
from statipy import StatipyClient
from jarvis.client.errors import ErrorMixin
from jarvis.client.events import EventMixin
@ -19,7 +20,7 @@ VAL_FMT = fmt(Fore.WHITE)
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
super().__init__(*args, **kwargs)
self.redis = redis

View file

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

View file

@ -2,6 +2,7 @@
import asyncio
from aiohttp import ClientSession
from beanie.operators import Set
from interactions import listen
from interactions.ext.prefixed_commands.context import PrefixedContext
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.models import Reminder, Setting
from jarvis_core.util.ansi import RESET, Fore, Format, fmt
from statipy.db import StaticStat
from jarvis import const
from jarvis.client.events.components import ComponentEventMixin
from jarvis.client.events.member import MemberEventMixin
from jarvis.client.events.message import MessageEventMixin
from jarvis.tracking import jarvis_info
from jarvis.utils import build_embed
KEY_FMT = fmt(Fore.GRAY)
@ -27,9 +28,11 @@ CMD_FMT = fmt(Fore.GREEN, Format.BOLD)
class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin):
async def _chunk_all(self) -> None:
"""Chunk all guilds."""
for guild in self.guilds:
self.logger.debug(f"Chunking guild {guild.name} <{guild.id}>")
await guild.chunk_guild()
self.logger.warn("Deprecated function, nothing will happen")
# for guild in self.guilds:
# 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:
self.logger.debug("Loading phishing domains")
@ -42,7 +45,20 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin):
@listen()
async def on_startup(self) -> None:
"""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:
if not self.synced:
await self._sync_domains()

View file

@ -3,13 +3,14 @@ import re
from datetime import datetime, timedelta, timezone
from aiohttp import ClientSession
from beanie.operators import Inc, Set
from interactions import listen
from interactions.api.events.discord import MessageCreate, MessageDelete, MessageUpdate
from interactions.client.utils.misc_utils import find_all
from interactions.models.discord.channel import DMChannel, GuildText
from interactions.models.discord.components import ActionRow, Button
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.user import Member
from jarvis_core.db import q
@ -24,11 +25,12 @@ from jarvis_core.db.models import (
Warning,
)
from jarvis_core.filters import invites, url
from statipy.db import Stat
from jarvis.branding import get_command_color
from jarvis.embeds.admin import warning_embed
from jarvis.tracking import malicious_tracker, warnings_tracker
from jarvis.utils import build_embed
from jarvis.tracking import WarningMetadata
class MessageEventMixin:
@ -99,8 +101,16 @@ class MessageEventMixin:
reason="Sent an invite link",
user=message.author.id,
).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
md = WarningMetadata(
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)
try:
await message.channel.send(embeds=embed)
@ -123,8 +133,16 @@ class MessageEventMixin:
reason="Sent a message with a filtered word",
user=message.author.id,
).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
md = WarningMetadata(
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)
try:
await message.reply(embeds=embed)
@ -169,8 +187,16 @@ class MessageEventMixin:
reason="Mass Mention",
user=message.author.id,
).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
md = WarningMetadata(
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)
try:
await message.channel.send(embeds=embed)
@ -233,8 +259,16 @@ class MessageEventMixin:
reason="Pinged a blocked role/user with a blocked role",
user=message.author.id,
).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
md = WarningMetadata(
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)
try:
await message.channel.send(embeds=embed)
@ -261,8 +295,16 @@ class MessageEventMixin:
reason="Phishing URL",
user=message.author.id,
).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
md = WarningMetadata(
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)
try:
await message.channel.send(embeds=embed)
@ -272,8 +314,6 @@ class MessageEventMixin:
await message.delete()
except Exception:
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:
@ -286,8 +326,8 @@ class MessageEventMixin:
fields=[EmbedField(name="URL", value=m)],
)
valid_button = Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}")
invalid_button = Button(style=ButtonStyles.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}")
valid_button = Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}")
invalid_button = Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}")
channel = await self.fetch_channel(1026918337554423868)
@ -331,8 +371,16 @@ class MessageEventMixin:
reason="Unsafe URL",
user=message.author.id,
).commit()
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
tracker.inc()
md = WarningMetadata(
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"])
embed = warning_embed(message.author, reasons, self.user)
try:
@ -343,8 +391,6 @@ class MessageEventMixin:
await message.delete()
except Exception:
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:
@ -357,8 +403,8 @@ class MessageEventMixin:
fields=[EmbedField(name="URL", value=m)],
)
valid_button = Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}")
invalid_button = Button(style=ButtonStyles.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}")
valid_button = Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}")
invalid_button = Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}")
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.models.discord.channel import GuildText
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -81,11 +81,11 @@ class AutoReactCog(Extension):
@slash_option(
name="channel",
description="Autoreact channel to add emote to",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@slash_option(name="thread", description="Create a thread?", opt_type=OptionTypes.BOOLEAN, required=False)
@slash_option(name="emote", description="Emote to add", opt_type=OptionTypes.STRING, 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=OptionType.STRING, required=False)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _autoreact_add(
self, ctx: InteractionContext, channel: GuildText, thread: bool = True, emote: str = None
@ -138,13 +138,13 @@ class AutoReactCog(Extension):
@slash_option(
name="channel",
description="Autoreact channel to remove emote from",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@slash_option(
name="emote",
description="Emote to remove (use all to delete)",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -179,7 +179,7 @@ class AutoReactCog(Extension):
@slash_option(
name="channel",
description="Channel to remove autoreact from",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -197,7 +197,7 @@ class AutoReactCog(Extension):
@slash_option(
name="channel",
description="Autoreact channel to list",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
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.user import User
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
SlashCommandChoice,
slash_command,
@ -84,12 +84,12 @@ class BanCog(ModcaseCog):
await ctx.send(embeds=embed)
@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="reason", description="Ban reason", opt_type=OptionTypes.STRING, 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=OptionType.STRING, required=True)
@slash_option(
name="btype",
description="Ban type",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
choices=[
SlashCommandChoice(name="Permanent", value="perm"),
@ -100,13 +100,13 @@ class BanCog(ModcaseCog):
@slash_option(
name="duration",
description="Temp ban duration in hours",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@slash_option(
name="delete_history",
description="Delete message history, format: 1w 3d 7h 5m 20s",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
)
@check(admin_or_permissions(Permissions.BAN_MEMBERS))
@ -197,8 +197,8 @@ class BanCog(ModcaseCog):
await ctx.guild.unban(user, reason="Ban was softban")
@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="reason", description="Unban reason", 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=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _unban(
self,
@ -288,7 +288,7 @@ class BanCog(ModcaseCog):
@slash_option(
name="btype",
description="Ban type",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
choices=[
SlashCommandChoice(name="All", value=0),
@ -300,7 +300,7 @@ class BanCog(ModcaseCog):
@slash_option(
name="active",
description="Active bans",
opt_type=OptionTypes.BOOLEAN,
opt_type=OptionType.BOOLEAN,
required=False,
)
@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.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -88,7 +88,7 @@ class FilterCog(Extension):
filter_ = SlashCommand(name="filter", description="Manage keyword filters")
@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))
async def _filter_create(self, ctx: InteractionContext, name: str) -> None:
return await self._edit_filter(ctx, name)
@ -98,7 +98,7 @@ class FilterCog(Extension):
name="name",
description="Filter to edit",
autocomplete=True,
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -110,7 +110,7 @@ class FilterCog(Extension):
name="name",
description="Filter to view",
autocomplete=True,
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
async def _filter_view(self, ctx: InteractionContext, name: str) -> None:
@ -128,7 +128,7 @@ class FilterCog(Extension):
name="name",
description="Filter to delete",
autocomplete=True,
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES))

View file

@ -2,7 +2,7 @@
from interactions import InteractionContext, Permissions
from interactions.models.discord.user import User
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
slash_command,
slash_option,
)
@ -18,8 +18,8 @@ class KickCog(ModcaseCog):
"""JARVIS KickCog."""
@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="reason", description="Kick reason", opt_type=OptionTypes.STRING, 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=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _kick(self, ctx: InteractionContext, user: User, reason: str) -> None:
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.enums import Permissions
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
slash_command,
slash_option,
)
@ -89,7 +89,7 @@ class LockCog(Extension):
@slash_option(
name="channel",
description="Channel to unlock",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=False,
)
@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.user import Member
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -108,11 +108,11 @@ class LockdownCog(Extension):
sub_cmd_name="start",
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(
name="duration",
description="Duration in minutes",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@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.user import Member
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -184,13 +184,13 @@ class CaseCog(Extension):
@slash_option(
name="user",
description="User to filter cases to",
opt_type=OptionTypes.USER,
opt_type=OptionType.USER,
required=False,
)
@slash_option(
name="closed",
description="Include closed cases",
opt_type=OptionTypes.BOOLEAN,
opt_type=OptionType.BOOLEAN,
required=False,
)
@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.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))
async def _case_show_summary(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -226,7 +226,7 @@ class CaseCog(Extension):
await ctx.send(embeds=embed)
@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))
async def _case_show_actions(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -239,7 +239,7 @@ class CaseCog(Extension):
await paginator.send(ctx)
@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))
async def _case_close(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -254,7 +254,7 @@ class CaseCog(Extension):
await ctx.send(embeds=embed)
@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))
async def _case_reopen(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -269,8 +269,8 @@ class CaseCog(Extension):
await ctx.send(embeds=embed)
@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="note", description="Note to add", 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=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -295,8 +295,8 @@ class CaseCog(Extension):
await ctx.send(embeds=embed)
@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="note", description="Note to add", opt_type=OptionTypes.STRING, 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=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS))
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))

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.user import Member
from interactions.models.internal.application_commands import (
CommandTypes,
OptionTypes,
CommandType,
OptionType,
SlashCommandChoice,
context_menu,
slash_command,
@ -41,7 +41,7 @@ class MuteCog(ModcaseCog):
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))
async def _timeout_cm(self, ctx: InteractionContext) -> None:
modal = Modal(
@ -103,23 +103,23 @@ class MuteCog(ModcaseCog):
await response.send("Unable to mute this user", ephemeral=True)
@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(
name="reason",
description="Reason for mute",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@slash_option(
name="time",
description="Duration of mute, default 1",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@slash_option(
name="scale",
description="Time scale, default Hour(s)",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
choices=[
SlashCommandChoice(name="Minute(s)", value=1),
@ -159,8 +159,8 @@ class MuteCog(ModcaseCog):
await ctx.send("Unable to mute this user", ephemeral=True)
@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="reason", description="Reason for unmute", opt_type=OptionTypes.STRING, 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=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS))
async def _unmute(self, ctx: InteractionContext, user: Member, reason: str) -> None:
if (

View file

@ -4,7 +4,7 @@ import logging
from interactions import Client, Extension, InteractionContext, Permissions
from interactions.models.discord.channel import GuildText
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
slash_command,
slash_option,
)
@ -26,7 +26,7 @@ class PurgeCog(Extension):
@slash_option(
name="amount",
description="Amount of messages to purge, default 10",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -51,13 +51,13 @@ class PurgeCog(Extension):
@slash_option(
name="channel",
description="Channel to autopurge",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@slash_option(
name="delay",
description="Seconds to keep message before purge, default 30",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -90,7 +90,7 @@ class PurgeCog(Extension):
@slash_option(
name="channel",
description="Channel to remove from autopurge",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
@ -110,13 +110,13 @@ class PurgeCog(Extension):
@slash_option(
name="channel",
description="Channel to update",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@slash_option(
name="delay",
description="New time to save",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=True,
)
@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.user import Member
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -33,7 +33,7 @@ class RolepingCog(Extension):
sub_cmd_name="add",
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))
async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None:
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.")
@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))
async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None:
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_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="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, 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=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
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))
@ -170,8 +170,8 @@ class RolepingCog(Extension):
sub_cmd_name="role",
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="role", description="Rolepinged role", 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=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None:
if bypass.id == ctx.guild.id:
@ -203,8 +203,8 @@ class RolepingCog(Extension):
sub_cmd_name="user",
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="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, 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=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
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))
@ -224,8 +224,8 @@ class RolepingCog(Extension):
sub_cmd_name="role",
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="role", description="Rolepinged role", 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=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
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))

View file

@ -5,12 +5,12 @@ from typing import Any
from interactions import AutocompleteContext, Client, Extension, InteractionContext
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.enums import Permissions
from interactions.models.discord.role import Role
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -55,7 +55,7 @@ class SettingsCog(Extension):
sub_cmd_name="modlog",
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))
async def _set_modlog(self, ctx: InteractionContext, channel: GuildText) -> None:
if not isinstance(channel, GuildText):
@ -71,7 +71,7 @@ class SettingsCog(Extension):
@slash_option(
name="channel",
description="Activitylog Channel",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -86,7 +86,7 @@ class SettingsCog(Extension):
@slash_option(
name="amount",
description="Amount of mentions (0 to disable)",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=True,
)
@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}")
@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))
async def _set_verified(self, ctx: InteractionContext, role: Role) -> None:
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}`")
@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))
async def _set_unverified(self, ctx: InteractionContext, role: Role) -> None:
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}`")
@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))
async def _set_invitedel(self, ctx: InteractionContext, active: bool) -> None:
await ctx.defer()
@ -138,7 +138,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. Automatic invite active: {active}")
@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))
async def _set_notify(self, ctx: InteractionContext, active: bool) -> None:
await ctx.defer()
@ -146,7 +146,7 @@ class SettingsCog(Extension):
await ctx.send(f"Settings applied. Notifications active: {active}")
@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))
async def _add_log_ignore(self, ctx: InteractionContext, channel: GuildText) -> None:
if not isinstance(channel, GuildText):
@ -224,7 +224,7 @@ class SettingsCog(Extension):
@slash_option(
name="channel",
description="Channel to stop ignoring",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@ -293,8 +293,8 @@ class SettingsCog(Extension):
async def _clear(self, ctx: InteractionContext) -> None:
components = [
ActionRow(
Button(style=ButtonStyles.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.RED, emoji="✖️", custom_id=f"{ctx.guild.id}|set_clear|no"),
Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"{ctx.guild.id}|set_clear|yes"),
)
]
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.models.discord.components import Button
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.user import Member
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
slash_command,
slash_option,
)
@ -30,18 +30,18 @@ class TemproleCog(Extension):
self.logger = logging.getLogger(__name__)
@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="role", description="Role to grant", opt_type=OptionTypes.ROLE, 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=OptionType.ROLE, required=True)
@slash_option(
name="duration",
description="Duration of temp role (i.e. 2 hours)",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@slash_option(
name="reason",
description="Reason for temporary role",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_ROLES))
@ -109,5 +109,5 @@ class TemproleCog(Extension):
fields=fields,
)
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)

View file

@ -4,7 +4,7 @@ import logging
from random import randint
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.command import cooldown
from interactions.models.internal.cooldowns import Buckets
@ -19,7 +19,7 @@ def create_layout() -> list:
for i in range(3):
label = "YES" if i == yes else "NO"
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(
Button(
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.user import Member
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
slash_command,
slash_option,
)
@ -25,17 +25,17 @@ class WarningCog(ModcaseCog):
"""JARVIS WarningCog."""
@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(
name="reason",
description="Reason for warning",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@slash_option(
name="duration",
description="Duration of warning in hours, default 24",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -67,11 +67,11 @@ class WarningCog(ModcaseCog):
await ctx.send(embeds=embed)
@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(
name="active",
description="View active only",
opt_type=OptionTypes.BOOLEAN,
opt_type=OptionType.BOOLEAN,
required=False,
)
@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.models.discord.components import Button
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 rich.console import Console
@ -86,7 +86,7 @@ class BotutilCog(Extension):
)
embed = build_embed(title="System Info", description="", fields=fields)
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)
@prefixed_command(name="update")
@ -118,7 +118,7 @@ class BotutilCog(Extension):
self.logger.info("Updates applied")
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:
await ctx.reply(content, embeds=embed, components=components)
else:
@ -131,7 +131,7 @@ class BotutilCog(Extension):
else:
embed = build_embed(title="Update Status", description="No changes applied", fields=[])
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)

View file

@ -11,10 +11,10 @@ from interactions import AutocompleteContext, Client, Extension, InteractionCont
from interactions.models.discord.channel import GuildChannel
from interactions.models.discord.components import ActionRow, Button
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.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -45,7 +45,7 @@ class RemindmeCog(Extension):
@slash_option(
name="private",
description="Send as DM?",
opt_type=OptionTypes.BOOLEAN,
opt_type=OptionType.BOOLEAN,
required=False,
)
async def _remindme(
@ -159,10 +159,10 @@ class RemindmeCog(Extension):
icon_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]
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)
private = private if private is not None else False
components = [ActionRow(*components)]
@ -211,14 +211,14 @@ class RemindmeCog(Extension):
return
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)
@reminders.subcommand(sub_cmd_name="delete", sub_cmd_description="Delete a reminder")
@slash_option(
name="content",
description="Content of the reminder",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@ -244,7 +244,7 @@ class RemindmeCog(Extension):
)
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:
await reminder.delete()
except Exception:
@ -258,7 +258,7 @@ class RemindmeCog(Extension):
@slash_option(
name="content",
description="Content of the reminder",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@ -283,7 +283,7 @@ class RemindmeCog(Extension):
)
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)
if reminder.remind_at <= datetime.now(tz=timezone.utc) and not reminder.active:
try:

View file

@ -10,7 +10,7 @@ from asyncpraw.models.reddit.submission import Subreddit as Sub
from asyncprawcore.exceptions import Forbidden, NotFound, Redirect
from interactions import Client, Extension, InteractionContext, Permissions
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 (
ActionRow,
StringSelectMenu,
@ -18,7 +18,7 @@ from interactions.models.discord.components import (
)
from interactions.models.discord.embed import Embed, EmbedField
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
SlashCommandChoice,
slash_option,
@ -143,14 +143,14 @@ class RedditCog(Extension):
@slash_option(
name="name",
description="Redditor name",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@slash_option(
name="channel",
description="Channel to post to",
opt_type=OptionTypes.CHANNEL,
channel_types=[ChannelTypes.GUILD_TEXT],
opt_type=OptionType.CHANNEL,
channel_types=[ChannelType.GUILD_TEXT],
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -255,14 +255,14 @@ class RedditCog(Extension):
@slash_option(
name="name",
description="Subreddit display name",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@slash_option(
name="channel",
description="Channel to post to",
opt_type=OptionTypes.CHANNEL,
channel_types=[ChannelTypes.GUILD_TEXT],
opt_type=OptionType.CHANNEL,
channel_types=[ChannelType.GUILD_TEXT],
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -371,7 +371,7 @@ class RedditCog(Extension):
await message.edit(components=components)
@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:
if not sub_name.match(name):
await ctx.send("Invalid Subreddit name", ephemeral=True)
@ -404,11 +404,11 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds)
@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(
name="time",
description="Top time",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
choices=[
SlashCommandChoice(name="All", value="all"),
@ -451,7 +451,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds)
@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:
if not sub_name.match(name):
await ctx.send("Invalid Subreddit name", ephemeral=True)
@ -484,7 +484,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds)
@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:
if not sub_name.match(name):
await ctx.send("Invalid Subreddit name", ephemeral=True)
@ -517,7 +517,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds)
@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:
await ctx.defer()
try:
@ -541,7 +541,7 @@ class RedditCog(Extension):
await ctx.send(embeds=embeds)
@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:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw"))
if not setting:

View file

@ -12,7 +12,7 @@ from interactions.models.discord.components import (
StringSelectOption,
)
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -45,17 +45,17 @@ class TwitterCog(Extension):
sub_cmd_name="follow",
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(
name="channel",
description="Channel to post tweets to",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@slash_option(
name="retweets",
description="Mirror re-tweets?",
opt_type=OptionTypes.BOOLEAN,
opt_type=OptionType.BOOLEAN,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -171,7 +171,7 @@ class TwitterCog(Extension):
@slash_option(
name="retweets",
description="Mirror re-tweets?",
opt_type=OptionTypes.BOOLEAN,
opt_type=OptionType.BOOLEAN,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))

View file

@ -9,19 +9,19 @@ from io import BytesIO
import numpy as np
from dateparser import parse
from interactions import Client, Extension, InteractionContext
from interactions import Client, Extension, SlashContext
from interactions import __version__ as ipyv
from interactions.models.discord.channel import GuildCategory, GuildText, GuildVoice
from interactions.models.discord.components import Button
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.guild import Guild
from interactions.models.discord.role import Role
from interactions.models.discord.user import User
from interactions.models.internal.application_commands import (
CommandTypes,
OptionTypes,
CommandType,
OptionType,
SlashCommand,
SlashCommandChoice,
context_menu,
@ -55,7 +55,7 @@ class UtilCog(Extension):
bot = SlashCommand(name="bot", description="Bot commands")
@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:
await ctx.send("Oh fuck no, go fuck yourself")
elif ctx.author.id == 840031256201003008:
@ -71,13 +71,15 @@ class UtilCog(Extension):
@bot.subcommand(sub_cmd_name="status", sub_cmd_description="Retrieve JARVIS status")
@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"
desc = (
f"All systems online"
f"\nConnected to **{len(self.bot.guilds)}** guilds"
f"\nListening for **{len(self.bot.application_commands)}** commands"
)
self.bot.logger.debug("Description made")
color = "#3498db"
fields = []
uptime = int(self.bot.start_time.timestamp())
@ -92,13 +94,14 @@ class UtilCog(Extension):
fields.append(
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()}"
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))
num_domains = len(self.bot.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)
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)
@bot.subcommand(
@ -106,18 +109,18 @@ class UtilCog(Extension):
sub_cmd_description="Get the current logo",
)
@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:
JARVIS_LOGO.save(image_bytes, "PNG")
image_bytes.seek(0)
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)
rc = SlashCommand(name="rc", description="Robot Camo emoji commands")
@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)
@rc.subcommand(
@ -127,10 +130,10 @@ class UtilCog(Extension):
@slash_option(
name="text",
description="Text to camo-ify",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
async def _rcauto(self, ctx: InteractionContext, text: str) -> None:
async def _rcauto(self, ctx: SlashContext, text: str) -> None:
to_send = ""
if len(text) == 1 and not re.match(r"^[A-Z0-9-()$@!?^'#. ]$", text.upper()):
await ctx.send("Please use ASCII characters.", ephemeral=True)
@ -148,7 +151,7 @@ class UtilCog(Extension):
else:
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:
user = ctx.author
@ -157,7 +160,7 @@ class UtilCog(Extension):
embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE")
embed.set_image(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)
@slash_command(
@ -167,10 +170,10 @@ class UtilCog(Extension):
@slash_option(
name="role",
description="Role to get info of",
opt_type=OptionTypes.ROLE,
opt_type=OptionType.ROLE,
required=True,
)
async def _roleinfo(self, ctx: InteractionContext, role: Role) -> None:
async def _roleinfo(self, ctx: SlashContext, role: Role) -> None:
fields = [
EmbedField(name="ID", value=str(role.id), inline=True),
EmbedField(name="Name", value=role.mention, inline=True),
@ -205,25 +208,25 @@ class UtilCog(Extension):
im.save(image_bytes, "PNG")
image_bytes.seek(0)
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)
@slash_command(name="avatar", description="Get a user avatar")
@slash_option(
name="user",
description="User to view avatar of",
opt_type=OptionTypes.USER,
opt_type=OptionType.USER,
required=False,
)
@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)
@context_menu(name="Avatar", context_type=CommandTypes.USER)
async def _avatar_menu(self, ctx: InteractionContext) -> None:
@context_menu(name="Avatar", context_type=CommandType.USER)
async def _avatar_menu(self, ctx: SlashContext) -> None:
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()
if not user:
user = ctx.author
@ -271,12 +274,12 @@ class UtilCog(Extension):
)
embed.set_thumbnail(url=user.display_avatar.url)
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)
@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)
async def _lmgtfy(self, ctx: InteractionContext, search: str) -> None:
@slash_option(name="search", description="What to search", opt_type=OptionType.STRING, required=True)
async def _lmgtfy(self, ctx: SlashContext, search: str) -> None:
url = "https://letmegooglethat.com/?q=" + urllib.parse.quote_plus(search)
await ctx.send(url)
@ -287,18 +290,18 @@ class UtilCog(Extension):
@slash_option(
name="user",
description="User to get info of",
opt_type=OptionTypes.USER,
opt_type=OptionType.USER,
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)
@context_menu(name="User Info", context_type=CommandTypes.USER)
async def _userinfo_menu(self, ctx: InteractionContext) -> None:
@context_menu(name="User Info", context_type=CommandType.USER)
async def _userinfo_menu(self, ctx: SlashContext) -> None:
await self._userinfo(ctx, ctx.target)
@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
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_thumbnail(url=guild.icon.url)
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)
@slash_command(
@ -344,13 +347,13 @@ class UtilCog(Extension):
@slash_option(
name="length",
description="Password length (default 32)",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
)
@slash_option(
name="chars",
description="Characters to include (default last option)",
opt_type=OptionTypes.INTEGER,
opt_type=OptionType.INTEGER,
required=False,
choices=[
SlashCommandChoice(name="A-Za-z", value=0),
@ -360,7 +363,7 @@ class UtilCog(Extension):
],
)
@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:
await ctx.send("Please limit password to 256 characters", ephemeral=True)
return
@ -381,8 +384,8 @@ class UtilCog(Extension):
)
@slash_command(name="pigpen", description="Encode a string into pigpen")
@slash_option(name="text", description="Text to encode", opt_type=OptionTypes.STRING, required=True)
async def _pigpen(self, ctx: InteractionContext, text: str) -> None:
@slash_option(name="text", description="Text to encode", opt_type=OptionType.STRING, required=True)
async def _pigpen(self, ctx: SlashContext, text: str) -> None:
outp = "`"
for c in text:
c = c.lower()
@ -397,9 +400,9 @@ class UtilCog(Extension):
await ctx.send(outp[:2000])
@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="private", description="Respond quietly?", opt_type=OptionTypes.BOOLEAN, required=False)
async def _timestamp(self, ctx: InteractionContext, string: str, private: bool = False) -> None:
@slash_option(name="string", description="String to convert", opt_type=OptionType.STRING, required=True)
@slash_option(name="private", description="Respond quietly?", opt_type=OptionType.BOOLEAN, required=False)
async def _timestamp(self, ctx: SlashContext, string: str, private: bool = False) -> None:
timestamp = parse(string)
if not timestamp:
await ctx.send("Valid time not found, try again", ephemeral=True)
@ -420,11 +423,11 @@ class UtilCog(Extension):
EmbedField(name="ISO8601", value=timestamp.isoformat()),
]
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)
@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(
f"""
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")
async def _privacy_terms(self, ctx: InteractionContext) -> None:
async def _privacy_terms(self, ctx: SlashContext) -> None:
await ctx.send(
"""
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.models.discord.components import Button
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 (
OptionTypes,
OptionType,
SlashCommand,
SlashCommandChoice,
slash_option,
@ -76,13 +76,13 @@ class CalcCog(Extension):
calc = SlashCommand(name="calc", description="Calculate some things")
@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:
if expression == "The answer to life, the universe, and everything":
fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(42)))
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)
return
try:
@ -97,18 +97,18 @@ class CalcCog(Extension):
fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(value)))
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)
convert = calc.group(name="convert", description="Conversion helpers")
@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(
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(
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(
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)}",
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)
@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(
name="from_currency",
description="Currency to convert from",
required=True,
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
autocomplete=True,
)
@slash_option(
name="to_currency",
description="Currency to convert to",
required=True,
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
autocomplete=True,
)
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)
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)
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)
ratio = which.get_rate(from_, to)
converted = value / ratio
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)
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)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@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(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@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:
await self._convert(ctx, from_unit, to_unit, value)
@ -370,12 +370,10 @@ class CalcCog(Extension):
@_calc_convert_time.autocomplete("from_unit")
@_calc_convert_volume.autocomplete("from_unit")
@_calc_convert_weight.autocomplete("from_unit")
async def _autocomplete_from_unit(
self, ctx: AutocompleteContext, from_unit: str, to_unit: str = None, value: int = 0
) -> None:
*_, which = ctx.invoked_name.split(" ")
async def _autocomplete_from_unit(self, ctx: AutocompleteContext) -> None:
*_, which = ctx.invoke_target.split(" ")
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_area.autocomplete("to_unit")
@ -388,12 +386,10 @@ class CalcCog(Extension):
@_calc_convert_time.autocomplete("to_unit")
@_calc_convert_volume.autocomplete("to_unit")
@_calc_convert_weight.autocomplete("to_unit")
async def _autocomplete_to_unit(
self, ctx: AutocompleteContext, from_unit: str, to_unit: str = None, value: int = 0
) -> None:
*_, which = ctx.invoked_name.split(" ")
async def _autocomplete_to_unit(self, ctx: AutocompleteContext) -> None:
*_, which = ctx.invoke_target.split(" ")
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]]:
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]
@_calc_convert_currency.autocomplete("from_currency")
async def _autocomplete_from_currency(
self, ctx: AutocompleteContext, from_currency: str = None, to_currency: str = None, value: int = 0
) -> None:
await ctx.send(choices=self._currency_autocomplete(from_currency))
async def _autocomplete_from_currency(self, ctx: AutocompleteContext) -> None:
await ctx.send(choices=self._currency_autocomplete(ctx.input_text))
@_calc_convert_currency.autocomplete("to_currency")
async def _autocomplete_to_currency(
self, ctx: AutocompleteContext, from_currency: str = None, to_currency: str = None, value: int = 0
) -> None:
await ctx.send(choices=self._currency_autocomplete(to_currency))
async def _autocomplete_to_currency(self, ctx: AutocompleteContext) -> None:
await ctx.send(choices=self._currency_autocomplete(ctx.input_text))
def setup(bot: Client) -> None:

View file

@ -15,11 +15,11 @@ from bson import ObjectId
from interactions import Client, Extension, InteractionContext
from interactions.models.discord.components import Button
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.message import Attachment
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
SlashCommandChoice,
slash_option,
@ -64,17 +64,17 @@ class DevCog(Extension):
@slash_option(
name="method",
description="Hash method",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in supported_hashes],
)
@slash_option(
name="data",
description="Data to hash",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
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)
async def _hash(self, ctx: InteractionContext, method: str, data: str = None, attach: Attachment = None) -> None:
if not data and not attach:
@ -117,21 +117,21 @@ class DevCog(Extension):
]
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)
@dev.subcommand(sub_cmd_name="uuid", sub_cmd_description="Generate a UUID")
@slash_option(
name="version",
description="UUID version",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in ["3", "4", "5"]],
)
@slash_option(
name="data",
description="Data for UUID version 3,5",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
)
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_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)
async def _uuid2ulid(self, ctx: InteractionContext, uuid: str) -> None:
if UUID_VERIFY.match(uuid):
@ -186,7 +186,7 @@ class DevCog(Extension):
sub_cmd_name="ulid2uuid",
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)
async def _ulid2uuid(self, ctx: InteractionContext, ulid: str) -> None:
if ULID_VERIFY.match(ulid):
@ -201,14 +201,14 @@ class DevCog(Extension):
@slash_option(
name="method",
description="Encode method",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods],
)
@slash_option(
name="data",
description="Data to encode",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
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),
]
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)
@dev.subcommand(sub_cmd_name="decode", sub_cmd_description="Decode some data")
@slash_option(
name="method",
description="Decode method",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods],
)
@slash_option(
name="data",
description="Data to decode",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
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),
]
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)
@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.models.discord.components import Button
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.message import Attachment
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -46,19 +46,19 @@ class ImageCog(Extension):
@slash_option(
name="target",
description="Target size, i.e. 200KB",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@slash_option(
name="attachment",
description="Image to resize",
opt_type=OptionTypes.ATTACHMENT,
opt_type=OptionType.ATTACHMENT,
required=False,
)
@slash_option(
name="url",
description="URL to download and resize",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
)
async def _resize(
@ -149,7 +149,7 @@ class ImageCog(Extension):
]
embed = build_embed(title=filename, description="", fields=fields)
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)

View file

@ -11,11 +11,11 @@ from interactions.models.discord.components import (
StringSelectMenu,
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.internal.application_commands import (
CommandTypes,
OptionTypes,
CommandType,
OptionType,
SlashCommand,
context_menu,
slash_option,
@ -75,7 +75,7 @@ class PinboardCog(Extension):
@slash_option(
name="channel",
description="Pinboard channel",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -111,7 +111,7 @@ class PinboardCog(Extension):
@slash_option(
name="channel",
description="Pinboard channel",
opt_type=OptionTypes.CHANNEL,
opt_type=OptionType.CHANNEL,
required=True,
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
@ -233,7 +233,7 @@ class PinboardCog(Extension):
embed.set_footer(text=ctx.guild.name + " | " + channel.name)
if 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)
await Star(
@ -254,7 +254,7 @@ class PinboardCog(Extension):
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))
async def _star_message(self, ctx: InteractionContext) -> None:
await self._star_add(ctx, message=str(ctx.target_id))

View file

@ -19,10 +19,10 @@ from interactions.models.discord.components import (
StringSelectOption,
)
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.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -53,13 +53,18 @@ class RolegiverCog(Extension):
if not guild:
await rolegiver.delete()
continue
role = await guild.fetch_role(rolegiver.role)
if not role:
await rolegiver.delete()
continue
if guild.id not in self.cache:
self.cache[guild.id] = {}
self.cache[guild.id][role.name] = role.id
roles = []
for role in rolegiver.roles:
role = await guild.fetch_role(role)
if role:
roles.append(role.id)
else:
continue
if guild.id not in self.cache:
self.cache[guild.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")
@ -67,7 +72,7 @@ class RolegiverCog(Extension):
sub_cmd_name="add",
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))
async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None:
if role.id == ctx.guild.id:
@ -120,7 +125,7 @@ class RolegiverCog(Extension):
embed.set_thumbnail(url=ctx.guild.icon.url)
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)
if ctx.guild.id not in self.cache:
@ -131,7 +136,7 @@ class RolegiverCog(Extension):
@slash_option(
name="role",
description="Name of role to add",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@ -212,7 +217,7 @@ class RolegiverCog(Extension):
embed.set_thumbnail(url=ctx.guild.icon.url)
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)
@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.models.discord.components import Button
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.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -39,7 +39,7 @@ class TagCog(Extension):
name="name",
description="Tag to get",
autocomplete=True,
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
async def _get(self, ctx: InteractionContext, name: str) -> None:
@ -125,7 +125,7 @@ class TagCog(Extension):
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)
if ctx.guild.id not in self.cache:
@ -136,7 +136,7 @@ class TagCog(Extension):
@slash_option(
name="name",
description="Tag name",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
autocomplete=True,
required=True,
)
@ -225,7 +225,7 @@ class TagCog(Extension):
name=ctx.author.username + "#" + ctx.author.discriminator,
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)
if tag.name not in self.cache[ctx.guild.id]:
self.cache[ctx.guild.id].remove(old_name)
@ -235,7 +235,7 @@ class TagCog(Extension):
@slash_option(
name="name",
description="Tag name",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@ -259,7 +259,7 @@ class TagCog(Extension):
@slash_option(
name="name",
description="Tag name",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
autocomplete=True,
)
@ -302,7 +302,7 @@ class TagCog(Extension):
name=f"{username}#{discrim}" if username else "Unknown User",
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)
@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)
names = "\n".join(f"`{t.name}`" for t in tags)
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)
@_get.autocomplete("name")

View file

@ -5,11 +5,11 @@ import re
import aiohttp
from interactions import Client, Extension, InteractionContext
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.user import Member, User
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -46,14 +46,14 @@ class CTCCog(Extension):
@ctc2.subcommand(sub_cmd_name="about")
@cooldown(bucket=Buckets.USER, rate=1, interval=30)
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)
@ctc2.subcommand(
sub_cmd_name="pw",
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)
async def _pw(self, ctx: InteractionContext, guess: str) -> None:
if len(guess) > 800:

View file

@ -9,7 +9,7 @@ from interactions import Client, Extension, InteractionContext
from interactions.client.utils import find
from interactions.models.discord.embed import EmbedField
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
slash_option,
)
@ -204,7 +204,7 @@ class DbrandCog(Extension):
@slash_option(
name="search",
description="Country search query (2 character code, country name, flag emoji)",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=True,
)
@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.user import Member
from interactions.models.internal.application_commands import (
OptionTypes,
OptionType,
SlashCommand,
SlashCommandChoice,
slash_command,
@ -40,7 +40,7 @@ class GitlabCog(Extension):
sub_cmd_name="issue",
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:
try:
issue = self.project.issues.get(int(id))
@ -102,7 +102,7 @@ class GitlabCog(Extension):
sub_cmd_name="milestone",
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:
try:
milestone = self.project.milestones.get(int(id))
@ -150,7 +150,7 @@ class GitlabCog(Extension):
sub_cmd_name="mr",
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:
try:
mr = self.project.mergerequests.get(int(id))
@ -251,7 +251,7 @@ class GitlabCog(Extension):
@slash_option(
name="state",
description="State of issues to get",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
choices=[
SlashCommandChoice(name="Open", value="opened"),
@ -305,7 +305,7 @@ class GitlabCog(Extension):
@slash_option(
name="state",
description="State of merge requests to get",
opt_type=OptionTypes.STRING,
opt_type=OptionType.STRING,
required=False,
choices=[
SlashCommandChoice(name="Open", value="opened"),
@ -391,7 +391,7 @@ class GitlabCog(Extension):
@slash_option(
name="user",
description="Credit someone else for this issue",
opt_type=OptionTypes.USER,
opt_type=OptionType.USER,
required=False,
)
async def _open_issue(self, ctx: InteractionContext, user: Member = None) -> None:

View file

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

View file

@ -3,13 +3,14 @@ import logging
from datetime import timedelta
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.user import Member
from jarvis_core.db import q
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
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 == "Warning":
tracker = warnings_tracker.labels(guild_id=ctx.guild.id, guild_name=ctx.guild.name)
tracker.inc()
md = WarningMetadata(
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)
if not user and not ctx.target_id:
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)
components = [
ActionRow(
Button(style=ButtonStyles.RED, emoji="✖️", custom_id="modcase|no"),
Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id="modcase|yes"),
Button(style=ButtonStyle.RED, emoji="✖️", custom_id="modcase|no"),
Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id="modcase|yes"),
)
]
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
beautifulsoup4 = "^4.11.1"
calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"} # Mine
nafftrack = {git = "https://github.com/zevaryx/nafftrack.git"} # Contributed
redis = "^4.4.0"
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]
black = {version = "^22.3.0", allow-prereleases = true}