Migrate to beanie

This commit is contained in:
Zeva Rose 2023-03-24 11:48:36 -06:00 committed by Zevaryx
parent 645432c0d4
commit c73732432b
31 changed files with 818 additions and 782 deletions

View file

@ -13,5 +13,6 @@ extend-ignore =
# Plugins we don't currently include: flake8-return # Plugins we don't currently include: flake8-return
R502, # do not implicitly return None in function able to return non-None value. R502, # do not implicitly return None in function able to return non-None value.
R503, # missing explicit return at the end of function ableto return non-None value. R503, # missing explicit return at the end of function ableto return non-None value.
R504, # unnecessary variable assignment, causes issues with Config
R505, B023, # Temporary R505, B023, # Temporary
max-line-length=100 max-line-length=100

View file

@ -8,12 +8,12 @@ from interactions import Intents
from jarvis_core.db import connect from jarvis_core.db import connect
from jarvis_core.log import get_logger from jarvis_core.log import get_logger
from redis import asyncio as aioredis from redis import asyncio as aioredis
from statipy.db import init_db from statipy.db import Stat, StaticStat
from jarvis import const from jarvis import const
from jarvis.client import Jarvis from jarvis.client import Jarvis
from jarvis.cogs import __path__ as cogs_path from jarvis.cogs import __path__ as cogs_path
from jarvis.config import JarvisConfig from jarvis.config import load_config
from jarvis.utils import get_extensions from jarvis.utils import get_extensions
__version__ = const.__version__ __version__ = const.__version__
@ -58,25 +58,25 @@ def jlogger(logger: logging.Logger, event: Any) -> None:
async def run() -> None: async def run() -> None:
"""Run JARVIS""" """Run JARVIS"""
# Configure logger # Configure logger
jconfig = JarvisConfig.from_yaml() config = load_config()
logger = get_logger("jarvis", show_locals=False) # jconfig.log_level == "DEBUG") logger = get_logger("jarvis", show_locals=False) # jconfig.log_level == "DEBUG")
logger.setLevel(jconfig.log_level) logger.setLevel(config.log_level)
file_handler = logging.FileHandler(filename="jarvis.log", encoding="UTF-8", mode="w") file_handler = logging.FileHandler(filename="jarvis.log", encoding="UTF-8", mode="w")
file_handler.setFormatter(logging.Formatter("[%(asctime)s] [%(name)s] [%(levelname)8s] %(message)s")) file_handler.setFormatter(logging.Formatter("[%(asctime)s] [%(name)s] [%(levelname)8s] %(message)s"))
logger.addHandler(file_handler) logger.addHandler(file_handler)
# Configure client # Configure client
intents = Intents.DEFAULT | Intents.MESSAGES | Intents.GUILD_MEMBERS | Intents.GUILD_MESSAGES intents = Intents.DEFAULT | Intents.MESSAGES | Intents.GUILD_MEMBERS | Intents.GUILD_MESSAGES
redis_config = jconfig.redis.copy() redis_config = config.redis.dict()
redis_host = redis_config.pop("host") redis_host = redis_config.pop("host")
redis = await aioredis.from_url(redis_host, decode_responses=True, **redis_config) redis = await aioredis.from_url(redis_host, decode_responses=True, **redis_config)
await init_db(**jconfig.mongo["connect"]) await connect(**config.mongo.dict(), testing=config.environment.value == "develop", extra_models=[StaticStat, Stat])
jarvis = Jarvis( jarvis = Jarvis(
intents=intents, intents=intents,
sync_interactions=jconfig.sync, sync_interactions=config.sync,
delete_unused_application_cmds=True, delete_unused_application_cmds=True,
send_command_tracebacks=False, send_command_tracebacks=False,
redis=redis, redis=redis,
@ -84,16 +84,15 @@ async def run() -> None:
) )
# External modules # External modules
if jconfig.jurigged: if config.jurigged:
logging.addLevelName(11, "\033[35mJURIG\033[0m ") logging.addLevelName(11, "\033[35mJURIG\033[0m ")
if jconfig.log_level == "INFO": if config.log_level == "INFO":
logger.setLevel(11) logger.setLevel(11)
jurigged.watch(pattern="jarvis/*.py", logger=partial(jlogger, logger)) jurigged.watch(pattern="jarvis/*.py", logger=partial(jlogger, logger))
# Initialize bot # Initialize bot
logger.info("Starting JARVIS") logger.info("Starting JARVIS")
logger.debug("Connecting to database") logger.debug("Connecting to database")
connect(**jconfig.mongo["connect"], testing=jconfig.mongo["database"] != "jarvis")
logger.debug("Loading configuration from database") logger.debug("Loading configuration from database")
# jconfig.get_db_config() # jconfig.get_db_config()
@ -106,6 +105,5 @@ async def run() -> None:
logger.debug("Loading statipy") logger.debug("Loading statipy")
jarvis.load_extension("statipy.ext") jarvis.load_extension("statipy.ext")
jarvis.max_messages = jconfig.max_messages
logger.debug("Running JARVIS") logger.debug("Running JARVIS")
await jarvis.astart(jconfig.token) await jarvis.astart(config.token)

View file

@ -12,7 +12,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Autoreact from jarvis_core.db.models import Autoreact
from jarvis.data.unicode import emoji_list from jarvis.data.unicode import emoji_list
@ -41,7 +40,7 @@ class AutoReactCog(Extension):
Returns: Returns:
Tuple of success? and error message Tuple of success? and error message
""" """
exists = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) exists = await Autoreact.find_one(Autoreact.guild == ctx.guild.id, Autoreact.channel == channel.id)
if exists: if exists:
return False, f"Autoreact already exists for {channel.mention}." return False, f"Autoreact already exists for {channel.mention}."
@ -51,7 +50,7 @@ class AutoReactCog(Extension):
reactions=[], reactions=[],
thread=thread, thread=thread,
admin=ctx.author.id, admin=ctx.author.id,
).commit() ).save()
return True, None return True, None
@ -66,7 +65,7 @@ class AutoReactCog(Extension):
Returns: Returns:
Success? Success?
""" """
ar = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) ar = await Autoreact.find_one(Autoreact.guild == ctx.guild.id, Autoreact.channel == channel.id)
if ar: if ar:
await ar.delete() await ar.delete()
return True return True
@ -105,10 +104,10 @@ class AutoReactCog(Extension):
if not find(lambda x: x.id == emoji_id, await ctx.guild.fetch_all_custom_emojis()): if not find(lambda x: x.id == emoji_id, await ctx.guild.fetch_all_custom_emojis()):
await ctx.send("Please use a custom emote from this server.", ephemeral=True) await ctx.send("Please use a custom emote from this server.", ephemeral=True)
return return
autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) autoreact = await Autoreact.find_one(Autoreact.guild == ctx.guild.id, Autoreact.channel == channel.id)
if not autoreact: if not autoreact:
await self.create_autoreact(ctx, channel, thread) await self.create_autoreact(ctx, channel, thread)
autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) autoreact = await Autoreact.find_one(Autoreact.guild == ctx.guild.id, Autoreact.channel == channel.id)
if emote and emote in autoreact.reactions: if emote and emote in autoreact.reactions:
await ctx.send( await ctx.send(
f"Emote already added to {channel.mention} autoreactions.", f"Emote already added to {channel.mention} autoreactions.",
@ -124,7 +123,7 @@ class AutoReactCog(Extension):
if emote: if emote:
autoreact.reactions.append(emote) autoreact.reactions.append(emote)
autoreact.thread = thread autoreact.thread = thread
await autoreact.commit() await autoreact.save()
message = "" message = ""
if emote: if emote:
message += f" Added {emote} to {channel.mention} autoreact." message += f" Added {emote} to {channel.mention} autoreact."
@ -149,7 +148,7 @@ class AutoReactCog(Extension):
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _autoreact_remove(self, ctx: InteractionContext, channel: GuildText, emote: str) -> None: async def _autoreact_remove(self, ctx: InteractionContext, channel: GuildText, emote: str) -> None:
autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) autoreact = await Autoreact.find_one(Autoreact.guild == ctx.guild.id, Autoreact.channel == channel.id)
if not autoreact: if not autoreact:
await ctx.send( await ctx.send(
f"Please create autoreact first with /autoreact add {channel.mention} {emote}", f"Please create autoreact first with /autoreact add {channel.mention} {emote}",
@ -167,7 +166,7 @@ class AutoReactCog(Extension):
return return
else: else:
autoreact.reactions.remove(emote) autoreact.reactions.remove(emote)
await autoreact.commit() await autoreact.save()
if len(autoreact.reactions) == 0 and not autoreact.thread: if len(autoreact.reactions) == 0 and not autoreact.thread:
await self.delete_autoreact(ctx, channel) await self.delete_autoreact(ctx, channel)
await ctx.send(f"Removed {emote} from {channel.mention} autoreact.") await ctx.send(f"Removed {emote} from {channel.mention} autoreact.")
@ -201,7 +200,7 @@ class AutoReactCog(Extension):
required=True, required=True,
) )
async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None: async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None:
exists = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) exists = await Autoreact.find_one(Autoreact.guild == ctx.guild.id, Autoreact.channel == channel.id)
if not exists: if not exists:
await ctx.send( await ctx.send(
f"Please create autoreact first with /autoreact add {channel.mention} <emote>", f"Please create autoreact first with /autoreact add {channel.mention} <emote>",

View file

@ -15,7 +15,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Ban, Unban from jarvis_core.db.models import Ban, Unban
from jarvis.branding import get_command_color from jarvis.branding import get_command_color
@ -53,7 +52,7 @@ class BanCog(ModcaseCog):
duration=duration, duration=duration,
active=active, active=active,
) )
await b.commit() await b.save()
embed = ban_embed( embed = ban_embed(
user=user, user=user,
@ -77,7 +76,7 @@ class BanCog(ModcaseCog):
admin=ctx.author.id, admin=ctx.author.id,
reason=reason, reason=reason,
) )
await u.commit() await u.save()
embed = unban_embed(user=user, admin=ctx.author, reason=reason) embed = unban_embed(user=user, admin=ctx.author, reason=reason)
@ -248,7 +247,9 @@ class BanCog(ModcaseCog):
# We take advantage of the previous checks to save CPU cycles # We take advantage of the previous checks to save CPU cycles
if not discord_ban_info: if not discord_ban_info:
if isinstance(user, User): if isinstance(user, User):
database_ban_info = await Ban.find_one(q(guild=ctx.guild.id, user=user.id, active=True)) database_ban_info = await Ban.find_one(
Ban.guild == ctx.guild.id, Ban.user == user.id, Ban.active is True
)
else: else:
search = { search = {
"guild": ctx.guild.id, "guild": ctx.guild.id,
@ -257,7 +258,8 @@ class BanCog(ModcaseCog):
} }
if discrim: if discrim:
search["discrim"] = discrim search["discrim"] = discrim
database_ban_info = await Ban.find_one(q(**search))
database_ban_info = await Ban.find_one(*[getattr(Ban, k) == v for k, v in search.items])
if not discord_ban_info and not database_ban_info: if not discord_ban_info and not database_ban_info:
await ctx.send(f"Unable to find user {orig_user}", ephemeral=True) await ctx.send(f"Unable to find user {orig_user}", ephemeral=True)
@ -311,7 +313,7 @@ class BanCog(ModcaseCog):
search["active"] = True search["active"] = True
if btype > 0: if btype > 0:
search["type"] = types[btype] search["type"] = types[btype]
bans = await Ban.find(search).sort([("created_at", -1)]).to_list(None) bans = await Ban.find(*[getattr(Ban, k) == v for k, v in search.items]).sort(-Ban.created_at).to_list()
db_bans = [] db_bans = []
fields = [] fields = []
for ban in bans: for ban in bans:

View file

@ -18,7 +18,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Filter from jarvis_core.db.models import Filter
from thefuzz import process from thefuzz import process
@ -36,7 +35,7 @@ class FilterCog(Extension):
content = "" content = ""
f: Filter = None f: Filter = None
if search: if search:
if f := await Filter.find_one(q(name=name, guild=ctx.guild.id)): if f := await Filter.find_one(Filter.name == name, Filter.guild == ctx.guild.id):
content = "\n".join(f.filters) content = "\n".join(f.filters)
kw = "Updating" if search else "Creating" kw = "Updating" if search else "Creating"
@ -68,7 +67,7 @@ class FilterCog(Extension):
else: else:
f.name = new_name f.name = new_name
f.filters = filters f.filters = filters
await f.commit() await f.save()
except Exception as e: except Exception as e:
await data.send(f"{e}", ephemeral=True) await data.send(f"{e}", ephemeral=True)
return return
@ -114,7 +113,7 @@ class FilterCog(Extension):
required=True, required=True,
) )
async def _filter_view(self, ctx: InteractionContext, name: str) -> None: async def _filter_view(self, ctx: InteractionContext, name: str) -> None:
f = await Filter.find_one(q(name=name, guild=ctx.guild.id)) f = await Filter.find_one(Filter.name == name, Filter.guild == ctx.guild.id)
if not f: if not f:
await ctx.send("That filter doesn't exist", ephemeral=True) await ctx.send("That filter doesn't exist", ephemeral=True)
return return
@ -133,7 +132,7 @@ class FilterCog(Extension):
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _filter_delete(self, ctx: InteractionContext, name: str) -> None: async def _filter_delete(self, ctx: InteractionContext, name: str) -> None:
f = await Filter.find_one(q(name=name, guild=ctx.guild.id)) f = await Filter.find_one(Filter.name == name, Filter.guild == ctx.guild.id)
if not f: if not f:
await ctx.send("That filter doesn't exist", ephemeral=True) await ctx.send("That filter doesn't exist", ephemeral=True)
return return
@ -151,7 +150,7 @@ class FilterCog(Extension):
@_filter_delete.autocomplete("name") @_filter_delete.autocomplete("name")
async def _autocomplete(self, ctx: AutocompleteContext, name: str) -> None: async def _autocomplete(self, ctx: AutocompleteContext, name: str) -> None:
if not self.cache.get(ctx.guild.id): if not self.cache.get(ctx.guild.id):
filters = await Filter.find(q(guild=ctx.guild.id)).to_list(None) filters = await Filter.find(Filter.guild == ctx.guild.id).to_list()
self.cache[ctx.guild.id] = [f.name for f in filters] self.cache[ctx.guild.id] = [f.name for f in filters]
results = process.extract(name, self.cache.get(ctx.guild.id), limit=25) results = process.extract(name, self.cache.get(ctx.guild.id), limit=25)
choices = [{"name": r[0], "value": r[0]} for r in results] choices = [{"name": r[0], "value": r[0]} for r in results]

View file

@ -55,5 +55,5 @@ class KickCog(ModcaseCog):
admin=ctx.author.id, admin=ctx.author.id,
guild=ctx.guild.id, guild=ctx.guild.id,
) )
await k.commit() await k.save()
await ctx.send(embeds=embed) await ctx.send(embeds=embed)

View file

@ -12,7 +12,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Lock, Permission from jarvis_core.db.models import Lock, Permission
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -82,7 +81,7 @@ class LockCog(Extension):
reason=reason, reason=reason,
duration=duration, duration=duration,
original_perms=current, original_perms=current,
).commit() ).save()
await ctx.send(f"{channel.mention} locked for {duration} minute(s)") await ctx.send(f"{channel.mention} locked for {duration} minute(s)")
@slash_command(name="unlock", description="Unlock a channel") @slash_command(name="unlock", description="Unlock a channel")
@ -100,7 +99,7 @@ class LockCog(Extension):
) -> None: ) -> None:
if not channel: if not channel:
channel = ctx.channel channel = ctx.channel
lock = await Lock.find_one(q(guild=ctx.guild.id, channel=channel.id, active=True)) lock = await Lock.find_one(Lock.guild == ctx.guild.id, Lock.channel == channel.id, Lock.active is True)
if not lock: if not lock:
await ctx.send(f"{channel.mention} not locked.", ephemeral=True) await ctx.send(f"{channel.mention} not locked.", ephemeral=True)
return return
@ -114,5 +113,5 @@ class LockCog(Extension):
await channel.delete_permission(target=overwrite, reason="Unlock") await channel.delete_permission(target=overwrite, reason="Unlock")
lock.active = False lock.active = False
await lock.commit() await lock.save()
await ctx.send(f"{channel.mention} unlocked") await ctx.send(f"{channel.mention} unlocked")

View file

@ -13,7 +13,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Lock, Lockdown, Permission from jarvis_core.db.models import Lock, Lockdown, Permission
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -41,7 +40,7 @@ async def lock(bot: Client, target: GuildChannel, admin: Member, reason: str, du
reason=reason, reason=reason,
duration=duration, duration=duration,
original_perms=current, original_perms=current,
).commit() ).save()
async def lock_all(bot: Client, guild: Guild, admin: Member, reason: str, duration: int) -> None: async def lock_all(bot: Client, guild: Guild, admin: Member, reason: str, duration: int) -> None:
@ -73,7 +72,7 @@ async def unlock_all(bot: Client, guild: Guild, admin: Member) -> None:
target: Target channel target: Target channel
admin: Admin who ended lockdown admin: Admin who ended lockdown
""" """
locks = Lock.find(q(guild=guild.id, active=True)) locks = Lock.find(Lock.guild == guild.id, Lock.active is True)
async for lock in locks: async for lock in locks:
target = await guild.fetch_channel(lock.channel) target = await guild.fetch_channel(lock.channel)
if target: if target:
@ -85,11 +84,11 @@ async def unlock_all(bot: Client, guild: Guild, admin: Member) -> None:
elif overwrite and not lock.original_perms: elif overwrite and not lock.original_perms:
await target.delete_permission(target=overwrite, reason="Lockdown end") await target.delete_permission(target=overwrite, reason="Lockdown end")
lock.active = False lock.active = False
await lock.commit() await lock.save()
lockdown = await Lockdown.find_one(q(guild=guild.id, active=True)) lockdown = await Lockdown.find_one(Lockdown.guild == guild.id, Lockdown.active is True)
if lockdown: if lockdown:
lockdown.active = False lockdown.active = False
await lockdown.commit() await lockdown.save()
class LockdownCog(Extension): class LockdownCog(Extension):
@ -130,7 +129,7 @@ class LockdownCog(Extension):
await ctx.send("Duration must be <= 7 days", ephemeral=True) await ctx.send("Duration must be <= 7 days", ephemeral=True)
return return
exists = await Lockdown.find_one(q(guild=ctx.guild.id, active=True)) exists = await Lockdown.find_one(Lockdown.guild == ctx.guild.id, Lockdown.active is True)
if exists: if exists:
await ctx.send("Server already in lockdown", ephemeral=True) await ctx.send("Server already in lockdown", ephemeral=True)
return return
@ -146,7 +145,7 @@ class LockdownCog(Extension):
guild=ctx.guild.id, guild=ctx.guild.id,
reason=reason, reason=reason,
original_perms=int(original_perms), original_perms=int(original_perms),
).commit() ).save()
await ctx.send("Server now in lockdown.") await ctx.send("Server now in lockdown.")
@lockdown.subcommand(sub_cmd_name="end", sub_cmd_description="End a lockdown") @lockdown.subcommand(sub_cmd_name="end", sub_cmd_description="End a lockdown")
@ -157,7 +156,7 @@ class LockdownCog(Extension):
) -> None: ) -> None:
await ctx.defer() await ctx.defer()
lockdown = await Lockdown.find_one(q(guild=ctx.guild.id, active=True)) lockdown = await Lockdown.find_one(Lockdown.guild == ctx.guild.id, Lockdown.active is True)
if not lockdown: if not lockdown:
await ctx.send("Server not in lockdown", ephemeral=True) await ctx.send("Server not in lockdown", ephemeral=True)
return return

View file

@ -11,7 +11,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Modlog, Note, actions from jarvis_core.db.models import Modlog, Note, actions
from rich.console import Console from rich.console import Console
from rich.table import Table from rich.table import Table
@ -56,7 +55,8 @@ class CaseCog(Extension):
action_output = "" action_output = ""
action_output_extra = "" action_output_extra = ""
for idx, action in enumerate(mod_case.actions): for idx, action in enumerate(mod_case.actions):
parent_action = await ACTIONS_LOOKUP[action.action_type].find_one(q(id=action.parent)) atype = ACTIONS_LOOKUP[action.action_type]
parent_action = await atype.find_one(atype.id == action.parent)
if not parent_action: if not parent_action:
action.orphaned = True action.orphaned = True
action_table.add_row(action.action_type.title(), "[N/A]", "[N/A]") action_table.add_row(action.action_type.title(), "[N/A]", "[N/A]")
@ -155,7 +155,8 @@ class CaseCog(Extension):
for action in mod_case.actions: for action in mod_case.actions:
if action.orphaned: if action.orphaned:
continue continue
parent_action = await ACTIONS_LOOKUP[action.action_type].find_one(q(id=action.parent)) atype = ACTIONS_LOOKUP[action.action_type]
parent_action = await atype.find_one(atype.id == action.parent)
if not parent_action: if not parent_action:
action.orphaned = True action.orphaned = True
continue continue
@ -195,12 +196,13 @@ class CaseCog(Extension):
) )
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _cases_list(self, ctx: InteractionContext, user: Optional[Member] = None, closed: bool = False) -> None: async def _cases_list(self, ctx: InteractionContext, user: Optional[Member] = None, closed: bool = False) -> None:
query = q(guild=ctx.guild.id) query = [Modlog.guild == ctx.guild.id]
if not closed: if not closed:
query.update(q(open=True)) query.append(Modlog.open is True)
if user: if user:
query.update(q(user=user.id)) query.append(Modlog.user == user.id)
cases = await Modlog.find(query).sort("created_at", -1).to_list(None)
cases = await Modlog.find(*query).sort(+Modlog.created_at).to_list()
if len(cases) == 0: if len(cases) == 0:
await ctx.send("No cases to view", ephemeral=True) await ctx.send("No cases to view", ephemeral=True)
@ -217,7 +219,7 @@ class CaseCog(Extension):
@slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_show_summary(self, ctx: InteractionContext, cid: str) -> None: async def _case_show_summary(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid)
if not case: if not case:
await ctx.send(f"Could not find case with ID {cid}", ephemeral=True) await ctx.send(f"Could not find case with ID {cid}", ephemeral=True)
return return
@ -229,7 +231,7 @@ class CaseCog(Extension):
@slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_show_actions(self, ctx: InteractionContext, cid: str) -> None: async def _case_show_actions(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid)
if not case: if not case:
await ctx.send(f"Could not find case with ID {cid}", ephemeral=True) await ctx.send(f"Could not find case with ID {cid}", ephemeral=True)
return return
@ -242,13 +244,13 @@ class CaseCog(Extension):
@slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_close(self, ctx: InteractionContext, cid: str) -> None: async def _case_close(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid)
if not case: if not case:
await ctx.send(f"Could not find case with ID {cid}", ephemeral=True) await ctx.send(f"Could not find case with ID {cid}", ephemeral=True)
return return
case.open = False case.open = False
await case.commit() await case.save()
embed = await self.get_summary_embed(case, ctx.guild) embed = await self.get_summary_embed(case, ctx.guild)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@ -257,13 +259,13 @@ class CaseCog(Extension):
@slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_reopen(self, ctx: InteractionContext, cid: str) -> None: async def _case_reopen(self, ctx: InteractionContext, cid: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid)
if not case: if not case:
await ctx.send(f"Could not find case with ID {cid}", ephemeral=True) await ctx.send(f"Could not find case with ID {cid}", ephemeral=True)
return return
case.open = True case.open = True
await case.commit() await case.save()
embed = await self.get_summary_embed(case, ctx.guild) embed = await self.get_summary_embed(case, ctx.guild)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@ -273,7 +275,7 @@ class CaseCog(Extension):
@slash_option(name="note", description="Note to add", 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)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None: async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid)
if not case: if not case:
await ctx.send(f"Could not find case with ID {cid}", ephemeral=True) await ctx.send(f"Could not find case with ID {cid}", ephemeral=True)
return return
@ -289,7 +291,7 @@ class CaseCog(Extension):
note = Note(admin=ctx.author.id, content=note) note = Note(admin=ctx.author.id, content=note)
case.notes.append(note) case.notes.append(note)
await case.commit() await case.save()
embed = await self.get_summary_embed(case, ctx.guild) embed = await self.get_summary_embed(case, ctx.guild)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@ -299,7 +301,7 @@ class CaseCog(Extension):
@slash_option(name="note", description="Note to add", 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)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None: async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, user=user.id, open=True)) case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.user == user.id, Modlog.open is True)
if case: if case:
await ctx.send(f"Case already open with ID `{case.nanoid}`", ephemeral=True) await ctx.send(f"Case already open with ID `{case.nanoid}`", ephemeral=True)
return return
@ -315,8 +317,7 @@ class CaseCog(Extension):
note = Note(admin=ctx.author.id, content=note) note = Note(admin=ctx.author.id, content=note)
case = Modlog(user=user.id, guild=ctx.guild.id, admin=ctx.author.id, notes=[note], actions=[]) case = Modlog(user=user.id, guild=ctx.guild.id, admin=ctx.author.id, notes=[note], actions=[])
await case.commit() await case.save()
await case.reload()
embed = await self.get_summary_embed(case, ctx.guild) embed = await self.get_summary_embed(case, ctx.guild)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)

View file

@ -37,7 +37,7 @@ class MuteCog(ModcaseCog):
guild=ctx.guild.id, guild=ctx.guild.id,
duration=duration, duration=duration,
active=True, active=True,
).commit() ).save()
return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild) return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild)

View file

@ -9,7 +9,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Autopurge, Purge from jarvis_core.db.models import Autopurge, Purge
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -45,7 +44,7 @@ class PurgeCog(Extension):
guild=ctx.guild.id, guild=ctx.guild.id,
admin=ctx.author.id, admin=ctx.author.id,
count=amount, count=amount,
).commit() ).save()
@slash_command(name="autopurge", sub_cmd_name="add", sub_cmd_description="Automatically purge messages") @slash_command(name="autopurge", sub_cmd_name="add", sub_cmd_description="Automatically purge messages")
@slash_option( @slash_option(
@ -72,7 +71,7 @@ class PurgeCog(Extension):
await ctx.send("Delay must be < 5 minutes", ephemeral=True) await ctx.send("Delay must be < 5 minutes", ephemeral=True)
return return
autopurge = await Autopurge.find_one(q(guild=ctx.guild.id, channel=channel.id)) autopurge = await Autopurge.find_one(Autopurge.guild == ctx.guild.id, Autopurge.channel == channel.id)
if autopurge: if autopurge:
await ctx.send("Autopurge already exists.", ephemeral=True) await ctx.send("Autopurge already exists.", ephemeral=True)
return return
@ -82,7 +81,7 @@ class PurgeCog(Extension):
channel=channel.id, channel=channel.id,
admin=ctx.author.id, admin=ctx.author.id,
delay=delay, delay=delay,
).commit() ).save()
await ctx.send(f"Autopurge set up on {channel.mention}, delay is {delay} seconds") await ctx.send(f"Autopurge set up on {channel.mention}, delay is {delay} seconds")
@ -95,7 +94,7 @@ class PurgeCog(Extension):
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _autopurge_remove(self, ctx: InteractionContext, channel: GuildText) -> None: async def _autopurge_remove(self, ctx: InteractionContext, channel: GuildText) -> None:
autopurge = await Autopurge.find_one(q(guild=ctx.guild.id, channel=channel.id)) autopurge = await Autopurge.find_one(Autopurge.guild == ctx.guild.id, Autopurge.channel == channel.id)
if not autopurge: if not autopurge:
await ctx.send("Autopurge does not exist.", ephemeral=True) await ctx.send("Autopurge does not exist.", ephemeral=True)
return return
@ -121,12 +120,12 @@ class PurgeCog(Extension):
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _autopurge_update(self, ctx: InteractionContext, channel: GuildText, delay: int) -> None: async def _autopurge_update(self, ctx: InteractionContext, channel: GuildText, delay: int) -> None:
autopurge = await Autopurge.find_one(q(guild=ctx.guild.id, channel=channel.id)) autopurge = await Autopurge.find_one(Autopurge.guild == ctx.guild.id, Autopurge.channel == channel.id)
if not autopurge: if not autopurge:
await ctx.send("Autopurge does not exist.", ephemeral=True) await ctx.send("Autopurge does not exist.", ephemeral=True)
return return
autopurge.delay = delay autopurge.delay = delay
await autopurge.commit() await autopurge.save()
await ctx.send(f"Autopurge delay updated to {delay} seconds on {channel.mention}.") await ctx.send(f"Autopurge delay updated to {delay} seconds on {channel.mention}.")

View file

@ -13,8 +13,7 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q from jarvis_core.db.models import Bypass, Roleping
from jarvis_core.db.models import Roleping
from jarvis.utils import build_embed from jarvis.utils import build_embed
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -36,7 +35,7 @@ class RolepingCog(Extension):
@slash_option(name="role", description="Role to add", opt_type=OptionType.ROLE, required=True) @slash_option(name="role", description="Role to add", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None: async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(Roleping.guild == ctx.guild.id, Roleping.role == role.id)
if roleping: if roleping:
await ctx.send(f"Role `{role.name}` already in roleping.", ephemeral=True) await ctx.send(f"Role `{role.name}` already in roleping.", ephemeral=True)
return return
@ -50,15 +49,15 @@ class RolepingCog(Extension):
guild=ctx.guild.id, guild=ctx.guild.id,
admin=ctx.author.id, admin=ctx.author.id,
active=True, active=True,
bypass={"roles": [], "users": []}, bypass=Bypass(),
).commit() ).save()
await ctx.send(f"Role `{role.name}` added to roleping.") await ctx.send(f"Role `{role.name}` added to roleping.")
@roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role") @roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role")
@slash_option(name="role", description="Role to remove", opt_type=OptionType.ROLE, required=True) @slash_option(name="role", description="Role to remove", opt_type=OptionType.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None: async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(Roleping.guild == ctx.guild.id, Roleping.role == role.id)
if not roleping: if not roleping:
await ctx.send("Roleping does not exist", ephemeral=True) await ctx.send("Roleping does not exist", ephemeral=True)
return return
@ -71,8 +70,7 @@ class RolepingCog(Extension):
@roleping.subcommand(sub_cmd_name="list", sub_cmd_description="Lick all blocklisted roles") @roleping.subcommand(sub_cmd_name="list", sub_cmd_description="Lick all blocklisted roles")
async def _roleping_list(self, ctx: InteractionContext) -> None: async def _roleping_list(self, ctx: InteractionContext) -> None:
rolepings = await Roleping.find(Roleping.guild == ctx.guild.id).to_list()
rolepings = await Roleping.find(q(guild=ctx.guild.id)).to_list(None)
if not rolepings: if not rolepings:
await ctx.send("No rolepings configured", ephemeral=True) await ctx.send("No rolepings configured", ephemeral=True)
return return
@ -83,10 +81,10 @@ class RolepingCog(Extension):
if not role: if not role:
await roleping.delete() await roleping.delete()
continue continue
broles = find_all(lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles) # noqa: B023 broles = find_all(lambda x: x.id in roleping.bypass.roles, ctx.guild.roles) # noqa: B023
bypass_roles = [r.mention or "||`[redacted]`||" for r in broles] bypass_roles = [r.mention or "||`[redacted]`||" for r in broles]
bypass_users = [ bypass_users = [
(await ctx.guild.fetch_member(u)).mention or "||`[redacted]`||" for u in roleping.bypass["users"] (await ctx.guild.fetch_member(u)).mention or "||`[redacted]`||" for u in roleping.bypass.users
] ]
bypass_roles = bypass_roles or ["None"] bypass_roles = bypass_roles or ["None"]
bypass_users = bypass_users or ["None"] bypass_users = bypass_users or ["None"]
@ -137,23 +135,23 @@ class RolepingCog(Extension):
@slash_option(name="role", description="Rolepinged role", 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)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None: async def _roleping_bypass_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(Roleping.guild == ctx.guild.id, role=role.id)
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
return return
if bypass.id in roleping.bypass["users"]: if bypass.id in roleping.bypass.users:
await ctx.send(f"{bypass.mention} already in bypass", ephemeral=True) await ctx.send(f"{bypass.mention} already in bypass", ephemeral=True)
return return
if len(roleping.bypass["users"]) == 10: if len(roleping.bypass.users) == 10:
await ctx.send( await ctx.send(
"Already have 10 users in bypass. Please consider using roles for roleping bypass", "Already have 10 users in bypass. Please consider using roles for roleping bypass",
ephemeral=True, ephemeral=True,
) )
return return
matching_role = list(filter(lambda x: x.id in roleping.bypass["roles"], bypass.roles)) matching_role = list(filter(lambda x: x.id in roleping.bypass.roles, bypass.roles))
if matching_role: if matching_role:
await ctx.send( await ctx.send(
@ -162,8 +160,8 @@ class RolepingCog(Extension):
) )
return return
roleping.bypass["users"].append(bypass.id) roleping.bypass.users.append(bypass.id)
await roleping.commit() await roleping.save()
await ctx.send(f"{bypass.display_name} user bypass added for `{role.name}`") await ctx.send(f"{bypass.display_name} user bypass added for `{role.name}`")
@bypass.subcommand( @bypass.subcommand(
@ -177,24 +175,24 @@ class RolepingCog(Extension):
if bypass.id == ctx.guild.id: if bypass.id == ctx.guild.id:
await ctx.send("Cannot add `@everyone` as a bypass", ephemeral=True) await ctx.send("Cannot add `@everyone` as a bypass", ephemeral=True)
return return
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(Roleping.guild == ctx.guild.id, Roleping.role == role.id)
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
return return
if bypass.id in roleping.bypass["roles"]: if bypass.id in roleping.bypass.roles:
await ctx.send(f"{bypass.mention} already in bypass", ephemeral=True) await ctx.send(f"{bypass.mention} already in bypass", ephemeral=True)
return return
if len(roleping.bypass["roles"]) == 10: if len(roleping.bypass.roles) == 10:
await ctx.send( await ctx.send(
"Already have 10 roles in bypass. " "Please consider consolidating roles for roleping bypass", "Already have 10 roles in bypass. " "Please consider consolidating roles for roleping bypass",
ephemeral=True, ephemeral=True,
) )
return return
roleping.bypass["roles"].append(bypass.id) roleping.bypass.roles.append(bypass.id)
await roleping.commit() await roleping.save()
await ctx.send(f"{bypass.name} role bypass added for `{role.name}`") await ctx.send(f"{bypass.name} role bypass added for `{role.name}`")
restore = roleping.group(name="restore", description="Remove a roleping bypass") restore = roleping.group(name="restore", description="Remove a roleping bypass")
@ -207,7 +205,7 @@ class RolepingCog(Extension):
@slash_option(name="role", description="Rolepinged role", 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)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_restore_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None: async def _roleping_restore_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None:
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping: Roleping = await Roleping.find_one(Roleping.guild == ctx.guild.id, Roleping.role == role.id)
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
return return
@ -217,7 +215,7 @@ class RolepingCog(Extension):
return return
roleping.bypass.users.remove(bypass.id) roleping.bypass.users.remove(bypass.id)
await roleping.commit() await roleping.save()
await ctx.send(f"{bypass.display_name} user bypass removed for `{role.name}`") await ctx.send(f"{bypass.display_name} user bypass removed for `{role.name}`")
@restore.subcommand( @restore.subcommand(
@ -228,7 +226,7 @@ class RolepingCog(Extension):
@slash_option(name="role", description="Rolepinged role", 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)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_restore_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None: async def _roleping_restore_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None:
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping: Roleping = await Roleping.find_one(Roleping.guild == ctx.guild.id, Roleping.role == role.id)
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
return return
@ -238,5 +236,5 @@ class RolepingCog(Extension):
return return
roleping.bypass.roles.remove(bypass.id) roleping.bypass.roles.remove(bypass.id)
await roleping.commit() await roleping.save()
await ctx.send(f"{bypass.display_name} user bypass removed for `{role.name}`") await ctx.send(f"{bypass.display_name} user bypass removed for `{role.name}`")

View file

@ -15,7 +15,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Setting from jarvis_core.db.models import Setting
from thefuzz import process from thefuzz import process
@ -32,17 +31,17 @@ class SettingsCog(Extension):
async def update_settings(self, setting: str, value: Any, guild: int) -> bool: async def update_settings(self, setting: str, value: Any, guild: int) -> bool:
"""Update a guild setting.""" """Update a guild setting."""
existing = await Setting.find_one(q(setting=setting, guild=guild)) existing = await Setting.find_one(Setting.setting == setting, Setting.guild == guild)
if not existing: if not existing:
existing = Setting(setting=setting, guild=guild, value=value) existing = Setting(setting=setting, guild=guild, value=value)
existing.value = value existing.value = value
updated = await existing.commit() updated = await existing.save()
return updated is not None return updated is not None
async def delete_settings(self, setting: str, guild: int) -> bool: async def delete_settings(self, setting: str, guild: int) -> bool:
"""Delete a guild setting.""" """Delete a guild setting."""
existing = await Setting.find_one(q(setting=setting, guild=guild)) existing = await Setting.find_one(Setting.setting == setting, Setting.guild == guild)
if existing: if existing:
return await existing.delete() return await existing.delete()
return False return False
@ -152,7 +151,7 @@ class SettingsCog(Extension):
if not isinstance(channel, GuildText): if not isinstance(channel, GuildText):
await ctx.send("Channel must be a GuildText", ephemeral=True) await ctx.send("Channel must be a GuildText", ephemeral=True)
return return
setting = await Setting.find_one(q(guild=ctx.guild.id, setting="log_ignore")) setting: Setting = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "log_ignore")
if not setting: if not setting:
setting = Setting(guild=ctx.guild.id, setting="log_ignore", value=[]) setting = Setting(guild=ctx.guild.id, setting="log_ignore", value=[])
if not setting.value: if not setting.value:
@ -161,7 +160,7 @@ class SettingsCog(Extension):
await ctx.send("Channel already ignored", ephemeral=True) await ctx.send("Channel already ignored", ephemeral=True)
return return
setting.value.append(channel.id) setting.value.append(channel.id)
await setting.commit(replace=True) await setting.save()
await ctx.send("Channel added to ActivityLog ignore list") await ctx.send("Channel added to ActivityLog ignore list")
# Unset # Unset
@ -231,17 +230,17 @@ class SettingsCog(Extension):
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _remove_log_ignore(self, ctx: InteractionContext, channel: str) -> None: async def _remove_log_ignore(self, ctx: InteractionContext, channel: str) -> None:
channel = int(channel) channel = int(channel)
setting = await Setting.find_one(q(guild=ctx.guild.id, setting="log_ignore")) setting = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "log_ignore")
if not setting or channel not in setting.value: if not setting or channel not in setting.value:
await ctx.send("Channel not being ignored", ephemeral=True) await ctx.send("Channel not being ignored", ephemeral=True)
return return
setting.value.remove(channel) setting.value.remove(channel)
await setting.commit(replace=True) await setting.save()
await ctx.send("Channel no longer being ignored") await ctx.send("Channel no longer being ignored")
@_remove_log_ignore.autocomplete(option_name="channel") @_remove_log_ignore.autocomplete(option_name="channel")
async def _channel_search(self, ctx: AutocompleteContext, channel: str) -> None: async def _channel_search(self, ctx: AutocompleteContext, channel: str) -> None:
setting = await Setting.find_one(q(guild=ctx.guild.id, setting="log_ignore")) setting = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "log_ignore")
if not setting: if not setting:
return {} return {}
channels = [ctx.guild.get_channel(x) for x in setting.value] channels = [ctx.guild.get_channel(x) for x in setting.value]
@ -252,7 +251,7 @@ class SettingsCog(Extension):
@settings.subcommand(sub_cmd_name="view", sub_cmd_description="View settings") @settings.subcommand(sub_cmd_name="view", sub_cmd_description="View settings")
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _view(self, ctx: InteractionContext) -> None: async def _view(self, ctx: InteractionContext) -> None:
settings = Setting.find(q(guild=ctx.guild.id)) settings = Setting.find(Setting.guild == ctx.guild.id)
fields = [] fields = []
async for setting in settings: async for setting in settings:
@ -305,7 +304,7 @@ class SettingsCog(Extension):
timeout=60 * 5, timeout=60 * 5,
) )
if context.ctx.custom_id == f"{ctx.guild.id}|set_clear|yes": if context.ctx.custom_id == f"{ctx.guild.id}|set_clear|yes":
async for setting in Setting.find(q(guild=ctx.guild.id)): async for setting in Setting.find(Setting.guild == ctx.guild.id):
await setting.delete() await setting.delete()
content = "Guild settings cleared" content = "Guild settings cleared"
else: else:

View file

@ -92,9 +92,7 @@ class TemproleCog(Extension):
return return
await user.add_role(role, reason=reason) await user.add_role(role, reason=reason)
await Temprole( await Temprole(guild=ctx.guild.id, user=user.id, role=role.id, admin=ctx.author.id, expires_at=duration).save()
guild=ctx.guild.id, user=user.id, role=role.id, admin=ctx.author.id, expires_at=duration
).commit()
ts = int(duration.timestamp()) ts = int(duration.timestamp())

View file

@ -8,7 +8,6 @@ from interactions.models.discord.components import Button, ButtonStyle, spread_t
from interactions.models.internal.application_commands import slash_command from interactions.models.internal.application_commands import slash_command
from interactions.models.internal.command import cooldown from interactions.models.internal.command import cooldown
from interactions.models.internal.cooldowns import Buckets from interactions.models.internal.cooldowns import Buckets
from jarvis_core.db import q
from jarvis_core.db.models import Setting from jarvis_core.db.models import Setting
@ -40,7 +39,7 @@ class VerifyCog(Extension):
@slash_command(name="verify", description="Verify that you've read the rules") @slash_command(name="verify", description="Verify that you've read the rules")
@cooldown(bucket=Buckets.USER, rate=1, interval=30) @cooldown(bucket=Buckets.USER, rate=1, interval=30)
async def _verify(self, ctx: InteractionContext) -> None: async def _verify(self, ctx: InteractionContext) -> None:
role = await Setting.find_one(q(guild=ctx.guild.id, setting="verified")) role = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "verified")
if not role: if not role:
message = await ctx.send("This guild has not enabled verification", ephemeral=True) message = await ctx.send("This guild has not enabled verification", ephemeral=True)
return return
@ -73,13 +72,13 @@ class VerifyCog(Extension):
for row in components: for row in components:
for component in row.components: for component in row.components:
component.disabled = True component.disabled = True
setting = await Setting.find_one(q(guild=ctx.guild.id, setting="verified")) setting = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "verified")
try: try:
role = await ctx.guild.fetch_role(setting.value) role = await ctx.guild.fetch_role(setting.value)
await ctx.author.add_role(role, reason="Verification passed") await ctx.author.add_role(role, reason="Verification passed")
except AttributeError: except AttributeError:
self.logger.warning("Verified role deleted before verification finished") self.logger.warning("Verified role deleted before verification finished")
setting = await Setting.find_one(q(guild=ctx.guild.id, setting="unverified")) setting = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "unverified")
if setting: if setting:
try: try:
role = await ctx.guild.fetch_role(setting.value) role = await ctx.guild.fetch_role(setting.value)

View file

@ -12,7 +12,6 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Warning from jarvis_core.db.models import Warning
from jarvis.embeds.admin import warning_embed from jarvis.embeds.admin import warning_embed
@ -62,7 +61,7 @@ class WarningCog(ModcaseCog):
duration=duration, duration=duration,
expires_at=expires_at, expires_at=expires_at,
active=True, active=True,
).commit() ).save()
embed = warning_embed(user, reason, ctx.author) embed = warning_embed(user, reason, ctx.author)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@ -78,13 +77,11 @@ class WarningCog(ModcaseCog):
async def _warnings(self, ctx: InteractionContext, user: Member, active: bool = True) -> None: async def _warnings(self, ctx: InteractionContext, user: Member, active: bool = True) -> None:
warnings = ( warnings = (
await Warning.find( await Warning.find(
q( Warning.user == user.id,
user=user.id, Warning.guild == ctx.guild.id,
guild=ctx.guild.id,
)
) )
.sort("created_at", -1) .sort(-Warning.created_at)
.to_list(None) .to_list()
) )
if len(warnings) == 0: if len(warnings) == 0:
await ctx.send("That user has no warnings.", ephemeral=True) await ctx.send("That user has no warnings.", ephemeral=True)

View file

@ -18,7 +18,6 @@ from interactions.models.internal.application_commands import (
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
from jarvis_core.db import q
from jarvis_core.db.models import Reminder from jarvis_core.db.models import Reminder
from thefuzz import process from thefuzz import process
@ -205,7 +204,7 @@ class RemindmeCog(Extension):
@reminders.subcommand(sub_cmd_name="list", sub_cmd_description="List reminders") @reminders.subcommand(sub_cmd_name="list", sub_cmd_description="List reminders")
async def _list(self, ctx: InteractionContext) -> None: async def _list(self, ctx: InteractionContext) -> None:
reminders = await Reminder.find(q(user=ctx.author.id, active=True)).to_list(None) reminders = await Reminder.find(Reminder.user == ctx.author.id, Reminder.active is True).to_list()
if not reminders: if not reminders:
await ctx.send("You have no reminders set.", ephemeral=True) await ctx.send("You have no reminders set.", ephemeral=True)
return return
@ -223,7 +222,7 @@ class RemindmeCog(Extension):
autocomplete=True, autocomplete=True,
) )
async def _delete(self, ctx: InteractionContext, content: str) -> None: async def _delete(self, ctx: InteractionContext, content: str) -> None:
reminder = await Reminder.find_one(q(_id=content)) reminder = await Reminder.find_one(Reminder.id == content)
if not reminder: if not reminder:
await ctx.send(f"Reminder `{content}` does not exist", ephemeral=True) await ctx.send(f"Reminder `{content}` does not exist", ephemeral=True)
return return
@ -263,7 +262,7 @@ class RemindmeCog(Extension):
autocomplete=True, autocomplete=True,
) )
async def _fetch(self, ctx: InteractionContext, content: str) -> None: async def _fetch(self, ctx: InteractionContext, content: str) -> None:
reminder = await Reminder.find_one(q(_id=content)) reminder = await Reminder.find_one(Reminder.id == content)
if not reminder: if not reminder:
await ctx.send(f"Reminder `{content}` does not exist", ephemeral=True) await ctx.send(f"Reminder `{content}` does not exist", ephemeral=True)
return return
@ -294,7 +293,7 @@ class RemindmeCog(Extension):
@_fetch.autocomplete("content") @_fetch.autocomplete("content")
@_delete.autocomplete("content") @_delete.autocomplete("content")
async def _search_reminders(self, ctx: AutocompleteContext, content: str) -> None: async def _search_reminders(self, ctx: AutocompleteContext, content: str) -> None:
reminders = await Reminder.find(q(user=ctx.author.id)).to_list(None) reminders = await Reminder.find(Reminder.user == ctx.author.id).to_list()
lookup = {r.message: str(r.id) for r in reminders} lookup = {r.message: str(r.id) for r in reminders}
results = process.extract(content, list(lookup.keys()), limit=5) results = process.extract(content, list(lookup.keys()), limit=5)
choices = [{"name": r[0], "value": lookup[r[0]]} for r in results] choices = [{"name": r[0], "value": lookup[r[0]]} for r in results]

View file

@ -24,17 +24,10 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q from jarvis_core.db.models import Subreddit, SubredditFollow, UserSetting
from jarvis_core.db.models import (
Redditor,
RedditorFollow,
Subreddit,
SubredditFollow,
UserSetting,
)
from jarvis import const from jarvis import const
from jarvis.config import JarvisConfig from jarvis.config import load_config
from jarvis.utils import build_embed from jarvis.utils import build_embed
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -50,9 +43,9 @@ class RedditCog(Extension):
def __init__(self, bot: Client): def __init__(self, bot: Client):
self.bot = bot self.bot = bot
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
config = JarvisConfig.from_yaml() config = load_config()
config.reddit["user_agent"] = config.reddit.get("user_agent", DEFAULT_USER_AGENT) config.reddit.user_agent = config.reddit.user_agent or DEFAULT_USER_AGENT
self.api = Reddit(**config.reddit) self.api = Reddit(**config.reddit.dict())
async def post_embeds(self, sub: Sub, post: Submission) -> Optional[List[Embed]]: async def post_embeds(self, sub: Sub, post: Submission) -> Optional[List[Embed]]:
""" """
@ -139,117 +132,122 @@ class RedditCog(Extension):
follow = reddit.group(name="follow", description="Add a follow") follow = reddit.group(name="follow", description="Add a follow")
unfollow = reddit.group(name="unfollow", description="Remove a follow") unfollow = reddit.group(name="unfollow", description="Remove a follow")
@follow.subcommand(sub_cmd_name="redditor", sub_cmd_description="Follow a Redditor") # Due to bugs and missing models, this section is commented out for the time being
@slash_option( # TODO:
name="name", # 1. Fix bugs
description="Redditor name", # 2. Migrate to beanie
opt_type=OptionType.STRING, #
required=True, # @follow.subcommand(sub_cmd_name="redditor", sub_cmd_description="Follow a Redditor")
) # @slash_option(
@slash_option( # name="name",
name="channel", # description="Redditor name",
description="Channel to post to", # opt_type=OptionType.STRING,
opt_type=OptionType.CHANNEL, # required=True,
channel_types=[ChannelType.GUILD_TEXT], # )
required=True, # @slash_option(
) # name="channel",
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) # description="Channel to post to",
async def _redditor_follow(self, ctx: InteractionContext, name: str, channel: GuildText) -> None: # opt_type=OptionType.CHANNEL,
if not user_name.match(name): # channel_types=[ChannelType.GUILD_TEXT],
await ctx.send("Invalid Redditor name", ephemeral=True) # required=True,
return # )
# @check(admin_or_permissions(Permissions.MANAGE_GUILD))
# async def _redditor_follow(self, ctx: InteractionContext, name: str, channel: GuildText) -> None:
# if not user_name.match(name):
# await ctx.send("Invalid Redditor name", ephemeral=True)
# return
if not isinstance(channel, GuildText): # if not isinstance(channel, GuildText):
await ctx.send("Channel must be a text channel", ephemeral=True) # await ctx.send("Channel must be a text channel", ephemeral=True)
return # return
try: # try:
redditor = await self.api.redditor(name) # redditor = await self.api.redditor(name)
await redditor.load() # await redditor.load()
except (NotFound, Forbidden, Redirect) as e: # except (NotFound, Forbidden, Redirect) as e:
self.logger.debug(f"Redditor {name} raised {e.__class__.__name__} on add") # self.logger.debug(f"Redditor {name} raised {e.__class__.__name__} on add")
await ctx.send("Redditor may be deleted or nonexistent.", ephemeral=True) # await ctx.send("Redditor may be deleted or nonexistent.", ephemeral=True)
return # return
exists = await RedditorFollow.find_one(q(name=redditor.name, guild=ctx.guild.id)) # exists = await RedditorFollow.find_one(q(name=redditor.name, guild=ctx.guild.id))
if exists: # if exists:
await ctx.send("Redditor already being followed in this guild", ephemeral=True) # await ctx.send("Redditor already being followed in this guild", ephemeral=True)
return # return
count = len([i async for i in SubredditFollow.find(q(guild=ctx.guild.id))]) # count = len([i async for i in SubredditFollow.find(q(guild=ctx.guild.id))])
if count >= 12: # if count >= 12:
await ctx.send("Cannot follow more than 12 Redditors", ephemeral=True) # await ctx.send("Cannot follow more than 12 Redditors", ephemeral=True)
return # return
sr = await Redditor.find_one(q(name=redditor.name)) # sr = await Redditor.find_one(q(name=redditor.name))
if not sr: # if not sr:
sr = Redditor(name=redditor.name) # sr = Redditor(name=redditor.name)
await sr.commit() # await sr.commit()
srf = RedditorFollow( # srf = RedditorFollow(
name=redditor.name, # name=redditor.name,
channel=channel.id, # channel=channel.id,
guild=ctx.guild.id, # guild=ctx.guild.id,
admin=ctx.author.id, # admin=ctx.author.id,
) # )
await srf.commit() # await srf.commit()
await ctx.send(f"Now following `u/{name}` in {channel.mention}") # await ctx.send(f"Now following `u/{name}` in {channel.mention}")
@unfollow.subcommand(sub_cmd_name="redditor", sub_cmd_description="Unfollow Redditor") # @unfollow.subcommand(sub_cmd_name="redditor", sub_cmd_description="Unfollow Redditor")
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) # @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _redditor_unfollow(self, ctx: InteractionContext) -> None: # async def _redditor_unfollow(self, ctx: InteractionContext) -> None:
subs = RedditorFollow.find(q(guild=ctx.guild.id)) # subs = RedditorFollow.find(q(guild=ctx.guild.id))
redditors = [] # redditors = []
async for sub in subs: # async for sub in subs:
redditors.append(sub) # redditors.append(sub)
if not redditors: # if not redditors:
await ctx.send("You need to follow a redditor first", ephemeral=True) # await ctx.send("You need to follow a redditor first", ephemeral=True)
return # return
options = [] # options = []
names = [] # names = []
for idx, redditor in enumerate(redditors): # for idx, redditor in enumerate(redditors):
sub = await Redditor.find_one(q(name=redditor.name)) # sub = await Redditor.find_one(q(name=redditor.name))
names.append(sub.name) # names.append(sub.name)
option = StringSelectOption(label=sub.name, value=str(idx)) # option = StringSelectOption(label=sub.name, value=str(idx))
options.append(option) # options.append(option)
select = StringSelectMenu(options=options, custom_id="to_delete", min_values=1, max_values=len(redditors)) # select = StringSelectMenu(options=options, custom_id="to_delete", min_values=1, max_values=len(redditors))
components = [ActionRow(select)] # components = [ActionRow(select)]
block = "\n".join(x for x in names) # block = "\n".join(x for x in names)
message = await ctx.send( # message = await ctx.send(
content=f"You are following the following redditors:\n```\n{block}\n```\n\n" # content=f"You are following the following redditors:\n```\n{block}\n```\n\n"
"Please choose redditors to unfollow", # "Please choose redditors to unfollow",
components=components, # components=components,
) # )
try: # try:
context = await self.bot.wait_for_component( # context = await self.bot.wait_for_component(
check=lambda x: ctx.author.id == x.ctx.author.id, # check=lambda x: ctx.author.id == x.ctx.author.id,
messages=message, # messages=message,
timeout=60 * 5, # timeout=60 * 5,
) # )
for to_delete in context.ctx.values: # for to_delete in context.ctx.values:
follow = get(redditors, guild=ctx.guild.id, name=names[int(to_delete)]) # follow = get(redditors, guild=ctx.guild.id, name=names[int(to_delete)])
try: # try:
await follow.delete() # await follow.delete()
except Exception: # except Exception:
self.logger.debug("Ignoring deletion error") # self.logger.debug("Ignoring deletion error")
for row in components: # for row in components:
for component in row.components: # for component in row.components:
component.disabled = True # component.disabled = True
block = "\n".join(names[int(x)] for x in context.ctx.values) # block = "\n".join(names[int(x)] for x in context.ctx.values)
await context.ctx.edit_origin( # await context.ctx.edit_origin(
content=f"Unfollowed the following:\n```\n{block}\n```", components=components # content=f"Unfollowed the following:\n```\n{block}\n```", components=components
) # )
except asyncio.TimeoutError: # except asyncio.TimeoutError:
for row in components: # for row in components:
for component in row.components: # for component in row.components:
component.disabled = True # component.disabled = True
await message.edit(components=components) # await message.edit(components=components)
@follow.subcommand(sub_cmd_name="subreddit", sub_cmd_description="Follow a Subreddit") @follow.subcommand(sub_cmd_name="subreddit", sub_cmd_description="Follow a Subreddit")
@slash_option( @slash_option(
@ -283,12 +281,14 @@ class RedditCog(Extension):
await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True) await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True)
return return
exists = await SubredditFollow.find_one(q(display_name=subreddit.display_name, guild=ctx.guild.id)) exists = await SubredditFollow.find_one(
SubredditFollow.display_name == subreddit.display_name, SubredditFollow.guild == ctx.guild.id
)
if exists: if exists:
await ctx.send("Subreddit already being followed in this guild", ephemeral=True) await ctx.send("Subreddit already being followed in this guild", ephemeral=True)
return return
count = len([i async for i in SubredditFollow.find(q(guild=ctx.guild.id))]) count = await SubredditFollow.find(SubredditFollow.guild == ctx.guild.id).count()
if count >= 12: if count >= 12:
await ctx.send("Cannot follow more than 12 Subreddits", ephemeral=True) await ctx.send("Cannot follow more than 12 Subreddits", ephemeral=True)
return return
@ -300,10 +300,10 @@ class RedditCog(Extension):
) )
return return
sr = await Subreddit.find_one(q(display_name=subreddit.display_name)) sr = await Subreddit.find_one(Subreddit.display_name == subreddit.display_name)
if not sr: if not sr:
sr = Subreddit(display_name=subreddit.display_name, over18=subreddit.over18) sr = Subreddit(display_name=subreddit.display_name, over18=subreddit.over18)
await sr.commit() await sr.save()
srf = SubredditFollow( srf = SubredditFollow(
display_name=subreddit.display_name, display_name=subreddit.display_name,
@ -311,17 +311,14 @@ class RedditCog(Extension):
guild=ctx.guild.id, guild=ctx.guild.id,
admin=ctx.author.id, admin=ctx.author.id,
) )
await srf.commit() await srf.save()
await ctx.send(f"Now following `r/{name}` in {channel.mention}") await ctx.send(f"Now following `r/{name}` in {channel.mention}")
@unfollow.subcommand(sub_cmd_name="subreddit", sub_cmd_description="Unfollow Subreddits") @unfollow.subcommand(sub_cmd_name="subreddit", sub_cmd_description="Unfollow Subreddits")
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _subreddit_unfollow(self, ctx: InteractionContext) -> None: async def _subreddit_unfollow(self, ctx: InteractionContext) -> None:
subs = SubredditFollow.find(q(guild=ctx.guild.id)) subreddits = await SubredditFollow.find(SubredditFollow.guild == ctx.guild.id).to_list()
subreddits = []
async for sub in subs:
subreddits.append(sub)
if not subreddits: if not subreddits:
await ctx.send("You need to follow a Subreddit first", ephemeral=True) await ctx.send("You need to follow a Subreddit first", ephemeral=True)
return return
@ -329,7 +326,7 @@ class RedditCog(Extension):
options = [] options = []
names = [] names = []
for idx, subreddit in enumerate(subreddits): for idx, subreddit in enumerate(subreddits):
sub = await Subreddit.find_one(q(display_name=subreddit.display_name)) sub = await Subreddit.find_one(Subreddit.display_name == subreddit.display_name)
names.append(sub.display_name) names.append(sub.display_name)
option = StringSelectOption(label=sub.display_name, value=str(idx)) option = StringSelectOption(label=sub.display_name, value=str(idx))
options.append(option) options.append(option)
@ -393,7 +390,9 @@ class RedditCog(Extension):
embeds = await self.post_embeds(subreddit, post) embeds = await self.post_embeds(subreddit, post)
if post.over_18 and not ctx.channel.nsfw: if post.over_18 and not ctx.channel.nsfw:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(
UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw"
)
if setting and setting.value: if setting and setting.value:
try: try:
await ctx.author.send(embeds=embeds) await ctx.author.send(embeds=embeds)
@ -440,7 +439,9 @@ class RedditCog(Extension):
embeds = await self.post_embeds(subreddit, post) embeds = await self.post_embeds(subreddit, post)
if post.over_18 and not ctx.channel.nsfw: if post.over_18 and not ctx.channel.nsfw:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(
UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw"
)
if setting and setting.value: if setting and setting.value:
try: try:
await ctx.author.send(embeds=embeds) await ctx.author.send(embeds=embeds)
@ -473,7 +474,9 @@ class RedditCog(Extension):
embeds = await self.post_embeds(subreddit, post) embeds = await self.post_embeds(subreddit, post)
if post.over_18 and not ctx.channel.nsfw: if post.over_18 and not ctx.channel.nsfw:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(
UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw"
)
if setting and setting.value: if setting and setting.value:
try: try:
await ctx.author.send(embeds=embeds) await ctx.author.send(embeds=embeds)
@ -506,7 +509,9 @@ class RedditCog(Extension):
embeds = await self.post_embeds(subreddit, post) embeds = await self.post_embeds(subreddit, post)
if post.over_18 and not ctx.channel.nsfw: if post.over_18 and not ctx.channel.nsfw:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(
UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw"
)
if setting and setting.value: if setting and setting.value:
try: try:
await ctx.author.send(embeds=embeds) await ctx.author.send(embeds=embeds)
@ -530,7 +535,9 @@ class RedditCog(Extension):
embeds = await self.post_embeds(post.subreddit, post) embeds = await self.post_embeds(post.subreddit, post)
if post.over_18 and not ctx.channel.nsfw: if post.over_18 and not ctx.channel.nsfw:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(
UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw"
)
if setting and setting.value: if setting and setting.value:
try: try:
await ctx.author.send(embeds=embeds) await ctx.author.send(embeds=embeds)
@ -543,15 +550,19 @@ class RedditCog(Extension):
@reddit.subcommand(sub_cmd_name="dm_nsfw", sub_cmd_description="DM NSFW posts if channel isn't NSFW") @reddit.subcommand(sub_cmd_name="dm_nsfw", sub_cmd_description="DM NSFW posts if channel isn't NSFW")
@slash_option(name="dm", description="Send DM?", opt_type=OptionType.BOOLEAN, required=True) @slash_option(name="dm", description="Send DM?", opt_type=OptionType.BOOLEAN, required=True)
async def _reddit_dm(self, ctx: InteractionContext, dm: bool) -> None: async def _reddit_dm(self, ctx: InteractionContext, dm: bool) -> None:
setting = await UserSetting.find_one(q(user=ctx.author.id, type="reddit", setting="dm_nsfw")) setting = await UserSetting.find_one(
UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw"
)
if not setting: if not setting:
setting = UserSetting(user=ctx.author.id, type="reddit", setting="dm_nsfw", value=dm) setting = UserSetting(user=ctx.author.id, type="reddit", setting="dm_nsfw", value=dm)
setting.value = dm setting.value = dm
await setting.commit() await setting.save()
await ctx.send(f"Reddit DM NSFW setting is now set to {dm}", ephemeral=True) await ctx.send(f"Reddit DM NSFW setting is now set to {dm}", ephemeral=True)
def setup(bot: Client) -> None: def setup(bot: Client) -> None:
"""Add RedditCog to JARVIS""" """Add RedditCog to JARVIS"""
if JarvisConfig.from_yaml().reddit: if load_config().reddit:
RedditCog(bot) RedditCog(bot)
else:
bot.logger.info("Missing Reddit configuration, not loading")

View file

@ -17,10 +17,9 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q
from jarvis_core.db.models import TwitterAccount, TwitterFollow from jarvis_core.db.models import TwitterAccount, TwitterFollow
from jarvis.config import JarvisConfig from jarvis.config import load_config
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -30,8 +29,8 @@ class TwitterCog(Extension):
def __init__(self, bot: Client): def __init__(self, bot: Client):
self.bot = bot self.bot = bot
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
config = JarvisConfig.from_yaml() config = load_config()
auth = tweepy.AppAuthHandler(config.twitter["consumer_key"], config.twitter["consumer_secret"]) auth = tweepy.AppAuthHandler(config.twitter.consumer_key, config.twitter.consumer_secret)
self.api = tweepy.API(auth) self.api = tweepy.API(auth)
self._guild_cache = {} self._guild_cache = {}
self._channel_cache = {} self._channel_cache = {}
@ -78,24 +77,26 @@ class TwitterCog(Extension):
await ctx.send("Unable to get user timeline. Are you sure the handle is correct?", ephemeral=True) await ctx.send("Unable to get user timeline. Are you sure the handle is correct?", ephemeral=True)
return return
exists = await TwitterFollow.find_one(q(twitter_id=account.id, guild=ctx.guild.id)) exists = await TwitterFollow.find_one(
TwitterFollow.twitter_id == account.id, TwitterFollow.guild == ctx.guild.id
)
if exists: if exists:
await ctx.send("Twitter account already being followed in this guild", ephemeral=True) await ctx.send("Twitter account already being followed in this guild", ephemeral=True)
return return
count = len([i async for i in TwitterFollow.find(q(guild=ctx.guild.id))]) count = await TwitterFollow.find(TwitterFollow.guild == ctx.guild.id).count()
if count >= 12: if count >= 12:
await ctx.send("Cannot follow more than 12 Twitter accounts", ephemeral=True) await ctx.send("Cannot follow more than 12 Twitter accounts", ephemeral=True)
return return
ta = await TwitterAccount.find_one(q(twitter_id=account.id)) ta = await TwitterAccount.find_one(TwitterAccount.twitter_id == account.id)
if not ta: if not ta:
ta = TwitterAccount( ta = TwitterAccount(
handle=account.screen_name, handle=account.screen_name,
twitter_id=account.id, twitter_id=account.id,
last_tweet=latest_tweet.id, last_tweet=latest_tweet.id,
) )
await ta.commit() await ta.save()
tf = TwitterFollow( tf = TwitterFollow(
twitter_id=account.id, twitter_id=account.id,
@ -105,14 +106,14 @@ class TwitterCog(Extension):
retweets=retweets, retweets=retweets,
) )
await tf.commit() await tf.save()
await ctx.send(f"Now following `@{handle}` in {channel.mention}") await ctx.send(f"Now following `@{handle}` in {channel.mention}")
@twitter.subcommand(sub_cmd_name="unfollow", sub_cmd_description="Unfollow Twitter accounts") @twitter.subcommand(sub_cmd_name="unfollow", sub_cmd_description="Unfollow Twitter accounts")
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _twitter_unfollow(self, ctx: InteractionContext) -> None: async def _twitter_unfollow(self, ctx: InteractionContext) -> None:
t = TwitterFollow.find(q(guild=ctx.guild.id)) t = TwitterFollow.find(TwitterFollow.guild == ctx.guild.id)
twitters = [] twitters = []
async for twitter in t: async for twitter in t:
twitters.append(twitter) twitters.append(twitter)
@ -123,7 +124,7 @@ class TwitterCog(Extension):
options = [] options = []
handlemap = {} handlemap = {}
for twitter in twitters: for twitter in twitters:
account = await TwitterAccount.find_one(q(twitter_id=twitter.twitter_id)) account = await TwitterAccount.find_one(TwitterAccount.twitter_id == twitter.twitter_id)
handlemap[str(twitter.twitter_id)] = account.handle handlemap[str(twitter.twitter_id)] = account.handle
option = StringSelectOption(label=account.handle, value=str(twitter.twitter_id)) option = StringSelectOption(label=account.handle, value=str(twitter.twitter_id))
options.append(option) options.append(option)
@ -176,7 +177,7 @@ class TwitterCog(Extension):
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _twitter_modify(self, ctx: InteractionContext, retweets: bool = True) -> None: async def _twitter_modify(self, ctx: InteractionContext, retweets: bool = True) -> None:
t = TwitterFollow.find(q(guild=ctx.guild.id)) t = TwitterFollow.find(TwitterFollow.guild == ctx.guild.id)
twitters = [] twitters = []
async for twitter in t: async for twitter in t:
twitters.append(twitter) twitters.append(twitter)
@ -187,7 +188,7 @@ class TwitterCog(Extension):
options = [] options = []
handlemap = {} handlemap = {}
for twitter in twitters: for twitter in twitters:
account = await TwitterAccount.find_one(q(twitter_id=twitter.id)) account = await TwitterAccount.find_one(TwitterAccount.twitter_id == twitter.id)
handlemap[str(twitter.twitter_id)] = account.handle handlemap[str(twitter.twitter_id)] = account.handle
option = StringSelectOption(label=account.handle, value=str(twitter.twitter_id)) option = StringSelectOption(label=account.handle, value=str(twitter.twitter_id))
options.append(option) options.append(option)
@ -211,11 +212,11 @@ class TwitterCog(Extension):
handlemap = {} handlemap = {}
for to_update in context.ctx.values: for to_update in context.ctx.values:
account = await TwitterAccount.find_one(q(twitter_id=int(to_update))) account = await TwitterAccount.find_one(TwitterAccount.twitter_id == int(to_update))
handlemap[str(twitter.twitter_id)] = account.handle handlemap[str(twitter.twitter_id)] = account.handle
t = get(twitters, guild=ctx.guild.id, twitter_id=int(to_update)) t = get(twitters, guild=ctx.guild.id, twitter_id=int(to_update))
t.update(q(retweets=True)) t.retweets = True
await t.commit() await t.save()
for row in components: for row in components:
for component in row.components: for component in row.components:
@ -239,5 +240,7 @@ class TwitterCog(Extension):
def setup(bot: Client) -> None: def setup(bot: Client) -> None:
"""Add TwitterCog to JARVIS""" """Add TwitterCog to JARVIS"""
if JarvisConfig.from_yaml().twitter: if load_config().twitter:
TwitterCog(bot) TwitterCog(bot)
else:
bot.logger.info("No Twitter configuration, not loading")

View file

@ -21,8 +21,7 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from interactions.models.internal.command import check from interactions.models.internal.command import check
from jarvis_core.db import q from jarvis_core.db.models import Pin, Pinboard
from jarvis_core.db.models import Star, Starboard
from jarvis.utils import build_embed from jarvis.utils import build_embed
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -43,16 +42,16 @@ class PinboardCog(Extension):
self.bot = bot self.bot = bot
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
async def _purge_starboard(self, ctx: InteractionContext, board: Starboard) -> None: async def _purge_starboard(self, ctx: InteractionContext, board: Pinboard) -> None:
channel = await ctx.guild.fetch_channel(board.channel) channel = await ctx.guild.fetch_channel(board.channel)
async for star in Star.find(q(starboard=channel.id, guild=ctx.guild.id)): async for pin in Pin.find(Pin.pinboard == channel.id, Pin.guild == ctx.guild.id):
if message := await channel.fetch_message(star.message): if message := await channel.fetch_message(pin.message):
try: try:
await message.delete() await message.delete()
await asyncio.sleep(1) # Avoid rate limits await asyncio.sleep(1) # Avoid rate limits
except (errors.Forbidden, errors.NotFound): except (errors.Forbidden, errors.NotFound):
self.logger.debug(f"Failed to delete star {star.id}'s message.") self.logger.debug(f"Failed to delete star {pin.id}'s message.")
await star.delete() await pin.delete()
pinboard = SlashCommand(name="pinboard", description="Extra pins! Manage pinboards") pinboard = SlashCommand(name="pinboard", description="Extra pins! Manage pinboards")
@ -60,12 +59,12 @@ class PinboardCog(Extension):
sub_cmd_name="list", sub_cmd_name="list",
sub_cmd_description="List all pinboards", sub_cmd_description="List all pinboards",
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD, Permissions.MANAGE_MESSAGES))
async def _list(self, ctx: InteractionContext) -> None: async def _list(self, ctx: InteractionContext) -> None:
starboards = await Starboard.find(q(guild=ctx.guild.id)).to_list(None) pinboards = await Pinboard.find(Pinboard.guild == ctx.guild.id).to_list()
if starboards != []: if pinboards != []:
message = "Available Pinboards:\n" message = "Available Pinboards:\n"
for s in starboards: for s in pinboards:
message += f"<#{s.channel}>\n" message += f"<#{s.channel}>\n"
await ctx.send(message) await ctx.send(message)
else: else:
@ -78,7 +77,7 @@ class PinboardCog(Extension):
opt_type=OptionType.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD, Permissions.MANAGE_MESSAGES))
async def _create(self, ctx: InteractionContext, channel: GuildText) -> None: async def _create(self, ctx: InteractionContext, channel: GuildText) -> None:
if channel not in ctx.guild.channels: if channel not in ctx.guild.channels:
await ctx.send( await ctx.send(
@ -90,21 +89,21 @@ class PinboardCog(Extension):
await ctx.send("Channel must be a GuildText", ephemeral=True) await ctx.send("Channel must be a GuildText", ephemeral=True)
return return
exists = await Starboard.find_one(q(channel=channel.id, guild=ctx.guild.id)) exists = await Pinboard.find_one(Pinboard.channel == channel.id, Pinboard.guild == ctx.guild.id)
if exists: if exists:
await ctx.send(f"Pinboard already exists at {channel.mention}.", ephemeral=True) await ctx.send(f"Pinboard already exists at {channel.mention}.", ephemeral=True)
return return
count = await Starboard.count_documents(q(guild=ctx.guild.id)) count = await Pinboard.find(Pinboard.guild == ctx.guild.id).count()
if count >= 25: if count >= 25:
await ctx.send("25 pinboard limit reached", ephemeral=True) await ctx.send("25 pinboard limit reached", ephemeral=True)
return return
await Starboard( await Pinboard(
guild=ctx.guild.id, guild=ctx.guild.id,
channel=channel.id, channel=channel.id,
admin=ctx.author.id, admin=ctx.author.id,
).commit() ).save()
await ctx.send(f"Pinboard created. Check it out at {channel.mention}.") await ctx.send(f"Pinboard created. Check it out at {channel.mention}.")
@pinboard.subcommand(sub_cmd_name="delete", sub_cmd_description="Delete a pinboard") @pinboard.subcommand(sub_cmd_name="delete", sub_cmd_description="Delete a pinboard")
@ -114,9 +113,9 @@ class PinboardCog(Extension):
opt_type=OptionType.CHANNEL, opt_type=OptionType.CHANNEL,
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD, Permissions.MANAGE_MESSAGES))
async def _delete(self, ctx: InteractionContext, channel: GuildText) -> None: async def _delete(self, ctx: InteractionContext, channel: GuildText) -> None:
found = await Starboard.find_one(q(channel=channel.id, guild=ctx.guild.id)) found = await Pinboard.find_one(Pinboard.channel == channel.id, Pinboard.guild == ctx.guild.id)
if found: if found:
await found.delete() await found.delete()
asyncio.create_task(self._purge_starboard(ctx, found)) asyncio.create_task(self._purge_starboard(ctx, found))
@ -132,8 +131,8 @@ class PinboardCog(Extension):
) -> None: ) -> None:
if not channel: if not channel:
channel = ctx.channel channel = ctx.channel
starboards = await Starboard.find(q(guild=ctx.guild.id)).to_list(None) pinboards = await Pinboard.find(Pinboard.guild == ctx.guild.id).to_list()
if not starboards: if not pinboards:
await ctx.send("No pinboards exist.", ephemeral=True) await ctx.send("No pinboards exist.", ephemeral=True)
return return
@ -149,18 +148,19 @@ class PinboardCog(Extension):
return return
channel_list = [] channel_list = []
to_delete = [] to_delete: list[Pinboard] = []
for starboard in starboards:
c = await ctx.guild.fetch_channel(starboard.channel) for pinboard in pinboards:
c = await ctx.guild.fetch_channel(pinboard.channel)
if c and isinstance(c, GuildText): if c and isinstance(c, GuildText):
channel_list.append(c) channel_list.append(c)
else: else:
self.logger.warning(f"Pinboard {starboard.channel} no longer valid in {ctx.guild.name}") self.logger.warning(f"Pinboard {pinboard.channel} no longer valid in {ctx.guild.name}")
to_delete.append(starboard) to_delete.append(pinboard)
for starboard in to_delete: for pinboard in to_delete:
try: try:
await starboard.delete() await pinboard.delete()
except Exception: except Exception:
self.logger.debug("Ignoring deletion error") self.logger.debug("Ignoring deletion error")
@ -187,25 +187,23 @@ class PinboardCog(Extension):
check=lambda x: ctx.author.id == x.context.author.id, check=lambda x: ctx.author.id == x.context.author.id,
) )
starboard = channel_list[int(com_ctx.context.values[0])] pinboard = channel_list[int(com_ctx.context.values[0])]
exists = await Star.find_one( exists = await Pin.find_one(
q( Pin.message == message.id,
message=message.id, Pin.channel == channel.id,
channel=channel.id, Pin.guild == ctx.guild.id,
guild=ctx.guild.id, Pin.pinboard == pinboard.id,
starboard=starboard.id,
)
) )
if exists: if exists:
await ctx.send( await ctx.send(
f"Message already sent to Pinboard {starboard.mention}", f"Message already sent to Pinboard {pinboard.mention}",
ephemeral=True, ephemeral=True,
) )
return return
count = await Star.count_documents(q(guild=ctx.guild.id, starboard=starboard.id)) count = await Pin.find(Pin.guild == ctx.guild.id, Pin.pinboard == pinboard.id).count()
content = message.content content = message.content
attachments = message.attachments attachments = message.attachments
@ -234,28 +232,28 @@ class PinboardCog(Extension):
if image_url: if image_url:
embed.set_image(url=image_url) embed.set_image(url=image_url)
star_components = Button(style=ButtonStyle.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) pin = await pinboard.send(embeds=embed, components=star_components)
await Star( await Pin(
index=count, index=count,
message=message.id, message=message.id,
channel=channel.id, channel=channel.id,
guild=ctx.guild.id, guild=ctx.guild.id,
starboard=starboard.id, pinboard=pinboard.id,
admin=ctx.author.id, admin=ctx.author.id,
star=star.id, pin=pin.id,
active=True, active=True,
).commit() ).save()
components[0].components[0].disabled = True components[0].components[0].disabled = True
await com_ctx.context.edit_origin( await com_ctx.context.edit_origin(
content=f"Message saved to Pinboard.\nSee it in {starboard.mention}", content=f"Message saved to Pinboard.\nSee it in {pinboard.mention}",
components=components, components=components,
) )
@context_menu(name="Pin Message", context_type=CommandType.MESSAGE) @context_menu(name="Pin Message", context_type=CommandType.MESSAGE)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD, Permissions.MANAGE_MESSAGES))
async def _star_message(self, ctx: InteractionContext) -> None: async def _star_message(self, ctx: InteractionContext) -> None:
await self._star_add(ctx, message=str(ctx.target_id)) await self._star_add(ctx, message=str(ctx.target_id))

View file

@ -28,7 +28,6 @@ from interactions.models.internal.application_commands import (
) )
from interactions.models.internal.command import check, cooldown from interactions.models.internal.command import check, cooldown
from interactions.models.internal.cooldowns import Buckets from interactions.models.internal.cooldowns import Buckets
from jarvis_core.db import q
from jarvis_core.db.models import Rolegiver from jarvis_core.db.models import Rolegiver
from thefuzz import process from thefuzz import process
@ -47,8 +46,7 @@ class RolegiverCog(Extension):
@listen() @listen()
async def on_ready(self) -> None: async def on_ready(self) -> None:
"""NAFF on_ready hook for loading cache.""" """NAFF on_ready hook for loading cache."""
all_rolegivers = await Rolegiver.find({}).to_list(None) async for rolegiver in Rolegiver.find():
for rolegiver in all_rolegivers:
guild = await self.bot.fetch_guild(rolegiver.guild) guild = await self.bot.fetch_guild(rolegiver.guild)
if not guild: if not guild:
await rolegiver.delete() await rolegiver.delete()
@ -64,7 +62,7 @@ class RolegiverCog(Extension):
self.cache[guild.id] = {} self.cache[guild.id] = {}
self.cache[guild.id][role.name] = role.id self.cache[guild.id][role.name] = role.id
rolegiver.roles = roles rolegiver.roles = roles
await rolegiver.commit() await rolegiver.save()
rolegiver = SlashCommand(name="rolegiver", description="Allow users to choose their own roles") rolegiver = SlashCommand(name="rolegiver", description="Allow users to choose their own roles")
@ -86,7 +84,7 @@ class RolegiverCog(Extension):
) )
return return
setting = await Rolegiver.find_one(q(guild=ctx.guild.id)) setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id)
if setting and setting.roles and role.id in setting.roles: if setting and setting.roles and role.id in setting.roles:
await ctx.send("Role already in rolegiver", ephemeral=True) await ctx.send("Role already in rolegiver", ephemeral=True)
return return
@ -97,7 +95,7 @@ class RolegiverCog(Extension):
setting.roles = setting.roles or [] setting.roles = setting.roles or []
setting.roles.append(role.id) setting.roles.append(role.id)
await setting.commit() await setting.save()
roles = [] roles = []
for role_id in setting.roles: for role_id in setting.roles:
@ -142,7 +140,7 @@ class RolegiverCog(Extension):
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _rolegiver_remove(self, ctx: InteractionContext, role: str) -> None: async def _rolegiver_remove(self, ctx: InteractionContext, role: str) -> None:
setting = await Rolegiver.find_one(q(guild=ctx.guild.id)) setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id)
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -155,7 +153,7 @@ class RolegiverCog(Extension):
return return
setting.value.remove(role_id) setting.value.remove(role_id)
await setting.commit() await setting.save()
role = await ctx.guild.fetch_role(role_id) role = await ctx.guild.fetch_role(role_id)
if not role: if not role:
await ctx.send("Role not found in guild", ephemeral=True) await ctx.send("Role not found in guild", ephemeral=True)
@ -169,7 +167,7 @@ class RolegiverCog(Extension):
to_remove.append(id_) to_remove.append(id_)
setting.value = [x for x in setting.value if x not in to_remove] setting.value = [x for x in setting.value if x not in to_remove]
await setting.commit() await setting.save()
fields = [ fields = [
EmbedField(name="Removed Role", value=role.mention), EmbedField(name="Removed Role", value=role.mention),
@ -191,7 +189,7 @@ class RolegiverCog(Extension):
@rolegiver.subcommand(sub_cmd_name="list", sub_cmd_description="List rolegiver roles") @rolegiver.subcommand(sub_cmd_name="list", sub_cmd_description="List rolegiver roles")
async def _rolegiver_list(self, ctx: InteractionContext) -> None: async def _rolegiver_list(self, ctx: InteractionContext) -> None:
setting = await Rolegiver.find_one(q(guild=ctx.guild.id)) setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id)
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -223,7 +221,7 @@ class RolegiverCog(Extension):
@rolegiver.subcommand(sub_cmd_name="get", sub_cmd_description="Get a role") @rolegiver.subcommand(sub_cmd_name="get", sub_cmd_description="Get a role")
@cooldown(bucket=Buckets.USER, rate=1, interval=10) @cooldown(bucket=Buckets.USER, rate=1, interval=10)
async def _role_get(self, ctx: InteractionContext) -> None: async def _role_get(self, ctx: InteractionContext) -> None:
setting = await Rolegiver.find_one(q(guild=ctx.guild.id)) setting = await Rolegiver.find_one(Rolegiver.quild == ctx.guild.id)
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -299,7 +297,7 @@ class RolegiverCog(Extension):
async def _role_remove(self, ctx: InteractionContext) -> None: async def _role_remove(self, ctx: InteractionContext) -> None:
user_roles = ctx.author.roles user_roles = ctx.author.roles
setting = await Rolegiver.find_one(q(guild=ctx.guild.id)) setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id)
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -374,14 +372,14 @@ class RolegiverCog(Extension):
@rolegiver.subcommand(sub_cmd_name="cleanup", sub_cmd_description="Removed deleted roles from rolegiver") @rolegiver.subcommand(sub_cmd_name="cleanup", sub_cmd_description="Removed deleted roles from rolegiver")
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _rolegiver_cleanup(self, ctx: InteractionContext) -> None: async def _rolegiver_cleanup(self, ctx: InteractionContext) -> None:
setting = await Rolegiver.find_one(q(guild=ctx.guild.id)) setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id)
if not setting or not setting.roles: if not setting or not setting.roles:
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
guild_role_ids = [r.id for r in ctx.guild.roles] guild_role_ids = [r.id for r in ctx.guild.roles]
for role_id in setting.roles: for role_id in setting.roles:
if role_id not in guild_role_ids: if role_id not in guild_role_ids:
setting.roles.remove(role_id) setting.roles.remove(role_id)
await setting.commit() await setting.save()
await ctx.send("Rolegiver cleanup finished") await ctx.send("Rolegiver cleanup finished")
self.cache.pop(ctx.guild.id, None) self.cache.pop(ctx.guild.id, None)
@ -389,8 +387,7 @@ class RolegiverCog(Extension):
@_rolegiver_remove.autocomplete("role") @_rolegiver_remove.autocomplete("role")
async def _autocomplete(self, ctx: AutocompleteContext, role: str) -> None: async def _autocomplete(self, ctx: AutocompleteContext, role: str) -> None:
if not self.cache.get(ctx.guild.id): if not self.cache.get(ctx.guild.id):
rolegivers = await Rolegiver.find(q(guild=ctx.guild.id)).to_list(None) async for rolegiver in Rolegiver.find(Rolegiver.guild == ctx.guild.id):
for rolegiver in rolegivers:
role = await ctx.guild.fetch_role(rolegiver.role) role = await ctx.guild.fetch_role(rolegiver.role)
if not role: if not role:
await rolegiver.delete() await rolegiver.delete()

View file

@ -14,7 +14,6 @@ from interactions.models.internal.application_commands import (
SlashCommand, SlashCommand,
slash_option, slash_option,
) )
from jarvis_core.db import q
from jarvis_core.db.models import Setting, Tag from jarvis_core.db.models import Setting, Tag
from thefuzz import process from thefuzz import process
@ -43,7 +42,7 @@ class TagCog(Extension):
required=True, required=True,
) )
async def _get(self, ctx: InteractionContext, name: str) -> None: async def _get(self, ctx: InteractionContext, name: str) -> None:
tag = await Tag.find_one(q(guild=ctx.guild.id, name=name)) tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name)
if not tag: if not tag:
await ctx.send("Well this is awkward, looks like the tag was deleted just now", ephemeral=True) await ctx.send("Well this is awkward, looks like the tag was deleted just now", ephemeral=True)
return return
@ -80,7 +79,7 @@ class TagCog(Extension):
except asyncio.TimeoutError: except asyncio.TimeoutError:
return return
noinvite = await Setting.find_one(q(guild=ctx.guild.id, setting="noinvite")) noinvite = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "noinvite")
if ( if (
(invites.search(content) or invites.search(name)) (invites.search(content) or invites.search(name))
@ -99,7 +98,7 @@ class TagCog(Extension):
await response.send("Tag name must only contain: [A-Za-z0-9_- ]", ephemeral=True) await response.send("Tag name must only contain: [A-Za-z0-9_- ]", ephemeral=True)
return return
tag = await Tag.find_one(q(guild=ctx.guild.id, name=name)) tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name)
if tag: if tag:
await response.send("That tag already exists", ephemeral=True) await response.send("That tag already exists", ephemeral=True)
return return
@ -112,7 +111,7 @@ class TagCog(Extension):
content=content, content=content,
guild=ctx.guild.id, guild=ctx.guild.id,
) )
await tag.commit() await tag.save()
embed = build_embed( embed = build_embed(
title="Tag Created", title="Tag Created",
@ -142,7 +141,7 @@ class TagCog(Extension):
) )
async def _edit(self, ctx: InteractionContext, name: str) -> None: async def _edit(self, ctx: InteractionContext, name: str) -> None:
old_name = name old_name = name
tag = await Tag.find_one(q(guild=ctx.guild.id, name=name)) tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name)
if not tag: if not tag:
await ctx.send("Tag not found", ephemeral=True) await ctx.send("Tag not found", ephemeral=True)
return return
@ -181,12 +180,12 @@ class TagCog(Extension):
except asyncio.TimeoutError: except asyncio.TimeoutError:
return return
new_tag = await Tag.find_one(q(guild=ctx.guild.id, name=name)) new_tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name)
if new_tag and new_tag.id != tag.id: if new_tag and new_tag.id != tag.id:
await ctx.send("That tag name is used by another tag, choose another name", ephemeral=True) await ctx.send("That tag name is used by another tag, choose another name", ephemeral=True)
return return
noinvite = await Setting.find_one(q(guild=ctx.guild.id, setting="noinvite")) noinvite = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "noinvite")
if ( if (
(invites.search(content) or invites.search(name)) (invites.search(content) or invites.search(name))
@ -210,7 +209,7 @@ class TagCog(Extension):
tag.edited_at = datetime.now(tz=timezone.utc) tag.edited_at = datetime.now(tz=timezone.utc)
tag.editor = ctx.author.id tag.editor = ctx.author.id
await tag.commit() await tag.save()
embed = build_embed( embed = build_embed(
title="Tag Updated", title="Tag Updated",
@ -240,7 +239,7 @@ class TagCog(Extension):
autocomplete=True, autocomplete=True,
) )
async def _delete(self, ctx: InteractionContext, name: str) -> None: async def _delete(self, ctx: InteractionContext, name: str) -> None:
tag = await Tag.find_one(q(guild=ctx.guild.id, name=name)) tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name)
if not tag: if not tag:
await ctx.send("Tag not found", ephemeral=True) await ctx.send("Tag not found", ephemeral=True)
return return
@ -264,7 +263,7 @@ class TagCog(Extension):
autocomplete=True, autocomplete=True,
) )
async def _info(self, ctx: InteractionContext, name: str) -> None: async def _info(self, ctx: InteractionContext, name: str) -> None:
tag = await Tag.find_one(q(guild=ctx.guild.id, name=name)) tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name)
if not tag: if not tag:
await ctx.send("Tag not found", ephemeral=True) await ctx.send("Tag not found", ephemeral=True)
return return
@ -307,7 +306,7 @@ class TagCog(Extension):
@tag.subcommand(sub_cmd_name="list", sub_cmd_description="List tag names") @tag.subcommand(sub_cmd_name="list", sub_cmd_description="List tag names")
async def _list(self, ctx: InteractionContext) -> None: async def _list(self, ctx: InteractionContext) -> None:
tags = await Tag.find(q(guild=ctx.guild.id)).to_list(None) tags = await Tag.find(Tag.guild == ctx.guild.id).to_list()
names = "\n".join(f"`{t.name}`" for t in tags) names = "\n".join(f"`{t.name}`" for t in tags)
embed = build_embed(title="All Tags", description=names, fields=[]) embed = build_embed(title="All Tags", description=names, fields=[])
components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
@ -319,7 +318,7 @@ class TagCog(Extension):
@_info.autocomplete("name") @_info.autocomplete("name")
async def _autocomplete(self, ctx: AutocompleteContext, name: str) -> None: async def _autocomplete(self, ctx: AutocompleteContext, name: str) -> None:
if not self.cache.get(ctx.guild.id): if not self.cache.get(ctx.guild.id):
tags = await Tag.find(q(guild=ctx.guild.id)).to_list(None) tags = await Tag.find(Tag.guild == ctx.guild.id).to_list()
self.cache[ctx.guild.id] = [tag.name for tag in tags] self.cache[ctx.guild.id] = [tag.name for tag in tags]
results = process.extract(name, self.cache.get(ctx.guild.id), limit=25) results = process.extract(name, self.cache.get(ctx.guild.id), limit=25)
choices = [{"name": r[0], "value": r[0]} for r in results] choices = [{"name": r[0], "value": r[0]} for r in results]

View file

@ -15,7 +15,6 @@ from interactions.models.internal.application_commands import (
) )
from interactions.models.internal.command import cooldown from interactions.models.internal.command import cooldown
from interactions.models.internal.cooldowns import Buckets from interactions.models.internal.cooldowns import Buckets
from jarvis_core.db import q
from jarvis_core.db.models import Guess from jarvis_core.db.models import Guess
from jarvis.utils import build_embed from jarvis.utils import build_embed
@ -74,7 +73,7 @@ class CTCCog(Extension):
ephemeral=True, ephemeral=True,
) )
return return
guessed = await Guess.find_one(q(guess=guess)) guessed = await Guess.find_one(Guess.guess == guess)
if guessed: if guessed:
await ctx.send("Already guessed, dipshit.", ephemeral=True) await ctx.send("Already guessed, dipshit.", ephemeral=True)
return return
@ -86,7 +85,7 @@ class CTCCog(Extension):
correct = True correct = True
else: else:
await ctx.send("Nope.", ephemeral=True) await ctx.send("Nope.", ephemeral=True)
await Guess(guess=guess, user=ctx.author.id, correct=correct).commit() await Guess(guess=guess, user=ctx.author.id, correct=correct).save()
@ctc2.subcommand( @ctc2.subcommand(
sub_cmd_name="guesses", sub_cmd_name="guesses",
@ -96,21 +95,21 @@ class CTCCog(Extension):
async def _guesses(self, ctx: InteractionContext) -> None: async def _guesses(self, ctx: InteractionContext) -> None:
await ctx.defer() await ctx.defer()
cache = {} cache = {}
guesses = Guess.find().sort("correct", -1).sort("id", -1) guesses = Guess.find().sort(-Guess.correct, -Guess.id)
fields = [] fields = []
async for guess in guesses: async for guess in guesses:
user = cache.get(guess["user"]) or await self.bot.fetch_user(guess["user"]) user = cache.get(guess.user) or await self.bot.fetch_user(guess.user)
if not user: if not user:
user = "[redacted]" user = "[redacted]"
if isinstance(user, (Member, User)): if isinstance(user, (Member, User)):
user = user.username + "#" + user.discriminator user = user.username + "#" + user.discriminator
cache[guess["user"]] = user cache[guess.user] = user
name = "Correctly" if guess["correct"] else "Incorrectly" name = "Correctly" if guess["correct"] else "Incorrectly"
name += " guessed by: " + user name += " guessed by: " + user
fields.append( fields.append(
EmbedField( EmbedField(
name=name, name=name,
value=guess["guess"] + "\n\u200b", value=guess.guess + "\n\u200b",
inline=False, inline=False,
) )
) )

View file

@ -18,7 +18,7 @@ from interactions.models.internal.cooldowns import Buckets
from thefuzz import process from thefuzz import process
from jarvis.branding import CUSTOM_EMOJIS from jarvis.branding import CUSTOM_EMOJIS
from jarvis.config import JarvisConfig from jarvis.config import load_config
from jarvis.data.dbrand import shipping_lookup from jarvis.data.dbrand import shipping_lookup
from jarvis.utils import build_embed from jarvis.utils import build_embed
@ -80,7 +80,7 @@ class DbrandCog(Extension):
self.base_url = "https://dbrand.com/" self.base_url = "https://dbrand.com/"
self._session = aiohttp.ClientSession() self._session = aiohttp.ClientSession()
self._session.headers.update({"Content-Type": "application/json"}) self._session.headers.update({"Content-Type": "application/json"})
self.api_url = JarvisConfig.from_yaml().urls["dbrand_shipping"] self.api_url = load_config().urls["dbrand_shipping"]
self.cache = {} self.cache = {}
def __del__(self): def __del__(self):
@ -350,5 +350,7 @@ class DbrandCog(Extension):
def setup(bot: Client) -> None: def setup(bot: Client) -> None:
"""Add dbrandcog to JARVIS""" """Add dbrandcog to JARVIS"""
if JarvisConfig.from_yaml().urls.get("dbrand_shipping"): if load_config().urls.get("dbrand_shipping"):
DbrandCog(bot) DbrandCog(bot)
else:
bot.logger.info("Missing dbrand shipping URL, not loading dbrand cog")

View file

@ -17,7 +17,7 @@ from interactions.models.internal.application_commands import (
slash_option, slash_option,
) )
from jarvis.config import JarvisConfig from jarvis.config import load_config
from jarvis.utils import build_embed from jarvis.utils import build_embed
guild_ids = [862402786116763668] guild_ids = [862402786116763668]
@ -29,7 +29,7 @@ class GitlabCog(Extension):
def __init__(self, bot: Client): def __init__(self, bot: Client):
self.bot = bot self.bot = bot
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
config = JarvisConfig.from_yaml() config = load_config()
self._gitlab = gitlab.Gitlab("https://git.zevaryx.com", private_token=config.gitlab_token) self._gitlab = gitlab.Gitlab("https://git.zevaryx.com", private_token=config.gitlab_token)
# JARVIS GitLab ID is 29 # JARVIS GitLab ID is 29
self.project = self._gitlab.projects.get(29) self.project = self._gitlab.projects.get(29)
@ -436,5 +436,7 @@ class GitlabCog(Extension):
def setup(bot: Client) -> None: def setup(bot: Client) -> None:
"""Add GitlabCog to JARVIS if Gitlab token exists.""" """Add GitlabCog to JARVIS if Gitlab token exists."""
if JarvisConfig.from_yaml().gitlab_token: if load_config().gitlab_token:
GitlabCog(bot) GitlabCog(bot)
else:
bot.logger.info("Missing GitLab token, ignoring GitLab cog")

View file

@ -1,90 +1,196 @@
"""Load the config for JARVIS""" """Load the config for JARVIS"""
from enum import Enum
from os import environ
from pathlib import Path
from typing import Optional
import orjson as json
import yaml
from dotenv import load_dotenv
from jarvis_core.util import find_all
from pydantic import BaseModel
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
from jarvis_core.config import Config class Mongo(BaseModel):
"""MongoDB config."""
host: list[str] | str = "localhost"
username: Optional[str] = None
password: Optional[str] = None
port: int = 27017
class JarvisConfig(Config): class Redis(BaseModel):
REQUIRED = ("token", "mongo", "redis") """Redis config."""
OPTIONAL = {
"urls": None,
"sync": False,
"log_level": "INFO",
"cogs": None,
"events": True,
"gitlab_token": None,
"max_messages": 1000,
"twitter": None,
"reddit": None,
"rook_token": None,
"jurigged": False,
}
ENV_REQUIRED = [
"TOKEN",
"MONGODB_HOST",
"MONGODB_USER",
"MONGODB_PASS",
"MONGODB_PORT",
"MONGODB_DATABASE",
"REDIS_HOST",
"REDIS_USER",
"REDIS_PASS",
]
ENV_OPTIONAL = {
"MAX_MESSAGES": 10000,
"GITLAB_TOKEN": None,
"LOG_LEVEL": "INFO",
"SYNC": False,
"ROOK": None,
"REDDIT_SECRET": None,
"REDDIT_CLIENT": None,
"TWITTER_CONSUMER_KEY": None,
"TWITTER_CONSUMER_SECRET": None,
"TWITTER_ACCESS_TOKEN": None,
"TWITTER_ACCESS_SECRET": None,
"URLS_DBRAND_SHIPPING": None,
"JURIGGED": False,
}
@classmethod host: str = "localhost"
def _process_env(cls, **kwargs) -> dict: username: Optional[str] = None
"""Process environment variables into usable info.""" password: Optional[str] = None
data = {}
mongo = {"connect": {}, "database": ""}
redis = {}
twitter = {}
reddit = {}
urls = {}
for item, value in kwargs.items():
if item.startswith("MONGODB"):
key = item.split("_")[1].lower()
if key == "database":
mongo[key] = value
else:
mongo["connect"][key] = value
elif item.startswith("REDIS"):
key = item.split("_")[1].lower()
redis[key] = value
elif item.startswith("TWITTER"):
key = "_".join(item.split("_")[1:]).lower()
twitter[key] = value
elif item.startswith("REDDIT"):
key = item.split("_")[1].lower()
reddit[key] = value
elif item.startswith("URLS_"):
key = "_".join(item.split("_")[1:]).lower()
urls[key] = value
else:
if item == "SYNC":
value = value.lower() == "True"
data[item.lower()] = value
data["mongo"] = mongo
data["redis"] = redis
if all(x is not None for x in reddit.values()):
data["reddit"] = reddit
if all(x is not None for x in twitter.values()):
data["twitter"] = twitter
data["urls"] = {k: v for k, v in urls if v}
return data class Mastodon(BaseModel):
"""Mastodon config."""
token: str
url: str
class Reddit(BaseModel):
"""Reddit config."""
user_agent: Optional[str] = None
client_secret: str
client_id: str
class Twitter(BaseModel):
"""Twitter config."""
consumer_key: str
consumer_secret: str
access_token: str
access_secret: str
bearer_token: str
class Environment(Enum):
"""JARVIS running environment."""
production = "production"
develop = "develop"
class Config(BaseModel):
"""JARVIS config model."""
token: str
environment: Environment = Environment.develop
mongo: Mongo
redis: Redis
mastodon: Optional[Mastodon] = None
reddit: Optional[Reddit] = None
twitter: Optional[Twitter] = None
urls: Optional[dict[str, str]] = None
sync: bool = False
log_level: str = "INFO"
jurigged: bool = False
_config: Config = None
def _load_json() -> Config | None:
path = Path("config.json")
config = None
if path.exists():
with path.open() as f:
j = json.loads(f.read())
config = Config(**j)
return config
def _load_yaml() -> Config | None:
path = Path("config.yaml")
config = None
if path.exists():
with path.open() as f:
y = yaml.load(f.read(), Loader=Loader)
config = Config(**y)
return config
def _load_env() -> Config | None:
load_dotenv()
data = {}
mongo = {}
redis = {}
mastodon = {}
twitter = {}
reddit = {}
urls = {}
mongo_keys = find_all(lambda x: x.upper().startswith("MONGO"), environ.keys())
redis_keys = find_all(lambda x: x.upper().startswith("REDIS"), environ.keys())
mastodon_keys = find_all(lambda x: x.upper().startswith("MASTODON"), environ.keys())
reddit_keys = find_all(lambda x: x.upper().startswith("REDDIT"), environ.keys())
twitter_keys = find_all(lambda x: x.upper().startswith("TWITTER"), environ.keys())
url_keys = find_all(lambda x: x.upper().startswith("URLS"), environ.keys())
config_keys = (
mongo_keys
+ redis_keys
+ mastodon_keys
+ reddit_keys
+ twitter_keys
+ url_keys
+ ["TOKEN", "SYNC", "LOG_LEVEL", "JURIGGED"]
)
for item, value in environ.items():
if item not in config_keys:
continue
if item in mongo_keys:
key = "_".join(item.split("_")[1:]).lower()
mongo[key] = value
elif item in redis_keys:
key = "_".join(item.split("_")[1:]).lower()
redis[key] = value
elif item in mastodon_keys:
key = "_".join(item.split("_")[1:]).lower()
mastodon[key] = value
elif item in twitter_keys:
key = "_".join(item.split("_")[1:]).lower()
twitter[key] = value
elif item in reddit_keys:
key = "_".join(item.split("_")[1:]).lower()
reddit[key] = value
elif item in url_keys:
key = "_".join(item.split("_")[1:]).lower()
urls[key] = value
else:
if item == "SYNC":
value = value.lower() in ["yes", "true"]
data[item.lower()] = value
data["mongo"] = mongo
data["redis"] = redis
if all(x is not None for x in reddit.values()):
data["reddit"] = reddit
if all(x is not None for x in twitter.values()):
data["twitter"] = twitter
if all(x is not None for x in mastodon.values()):
data["mastodon"] = mastodon
data["urls"] = {k: v for k, v in urls if v}
return Config(**data)
def load_config(method: Optional[str] = None) -> Config:
"""
Load the config using the specified method first
Args:
method: Method to use first
"""
global _config
if _config is not None:
return _config
methods = {"yaml": _load_yaml, "json": _load_json, "env": _load_env}
method_names = list(methods.keys())
if method and method in method_names:
method_names.remove(method)
method_names.insert(0, method)
for method in method_names:
if _config := methods[method]():
return _config
raise FileNotFoundError("Missing one of: config.yaml, config.json, .env")

View file

@ -8,7 +8,6 @@ from interactions.models.discord.guild import AuditLogEntry
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from jarvis.branding import PRIMARY_COLOR from jarvis.branding import PRIMARY_COLOR
from jarvis.config import JarvisConfig
def build_embed( def build_embed(
@ -66,8 +65,7 @@ def modlog_embed(
def get_extensions(path: str) -> list: def get_extensions(path: str) -> list:
"""Get JARVIS cogs.""" """Get JARVIS cogs."""
config = JarvisConfig.from_yaml() vals = [x.name for x in iter_modules(path)]
vals = config.cogs or [x.name for x in iter_modules(path)]
return [f"jarvis.cogs.{x}" for x in vals] return [f"jarvis.cogs.{x}" for x in vals]

View file

@ -6,7 +6,6 @@ from interactions import Client, Extension, InteractionContext
from interactions.models.discord.components import ActionRow, Button, ButtonStyle from interactions.models.discord.components import ActionRow, Button, ButtonStyle
from interactions.models.discord.embed import EmbedField from interactions.models.discord.embed import EmbedField
from interactions.models.discord.user import Member from interactions.models.discord.user import Member
from jarvis_core.db import q
from jarvis_core.db.models import Action, Ban, Kick, Modlog, Mute, Setting, Warning from jarvis_core.db.models import Action, Ban, Kick, Modlog, Mute, Setting, Warning
from statipy.db import Stat from statipy.db import Stat
@ -45,13 +44,12 @@ class ModcaseCog(Extension):
md = WarningMetadata( md = WarningMetadata(
client_id=self.user.id, client_id=self.user.id,
client_name=self.client_name, client_name=self.client_name,
name="warning",
type="manual", type="manual",
guild_id=message.guild.id, guild_id=ctx.guild.id,
guild_name=message.guild.name, guild_name=ctx.guild.name,
value=1, value=1,
) )
await Stat(meta=md).insert() await Stat(meta=md, name="warning").insert()
user = kwargs.pop("user", None) user = kwargs.pop("user", None)
if not user and not ctx.target_id: if not user and not ctx.target_id:
self.logger.warning("Admin action %s missing user, exiting", name) self.logger.warning("Admin action %s missing user, exiting", name)
@ -69,12 +67,16 @@ class ModcaseCog(Extension):
self.logger.warning("Unsupported action %s, exiting", name) self.logger.warning("Unsupported action %s, exiting", name)
return return
action = await coll.find_one(q(user=user.id, guild=ctx.guild_id, active=True), sort=[("_id", -1)]) action = await coll.find_one(
coll.user == user.id, coll.guild == ctx.guild.id, coll.active is True, sort=[("_id", -1)]
)
if not action: if not action:
self.logger.warning("Missing action %s, exiting", name) self.logger.warning("Missing action %s, exiting", name)
return return
notify = await Setting.find_one(q(guild=ctx.guild.id, setting="notify", value=True)) notify = await Setting.find_one(
Setting.guild == ctx.guild.id, Setting.setting == "notify", Setting.value is True
)
if notify and name not in ("Kick", "Ban"): # Ignore Kick and Ban, as these are unique if notify and name not in ("Kick", "Ban"): # Ignore Kick and Ban, as these are unique
fields = ( fields = (
EmbedField(name="Action Type", value=name, inline=False), EmbedField(name="Action Type", value=name, inline=False),
@ -96,14 +98,15 @@ class ModcaseCog(Extension):
except Exception: except Exception:
self.logger.debug("User not warned of action due to closed DMs") self.logger.debug("User not warned of action due to closed DMs")
modlog = await Modlog.find_one(q(user=user.id, guild=ctx.guild.id, open=True)) modlog = await Modlog.find_one(Modlog.user == user.id, Modlog.guild == ctx.guild.id, Modlog.open is True)
if modlog: if modlog:
m_action = Action(action_type=name.lower(), parent=action.id) m_action = Action(action_type=name.lower(), parent=action.id)
modlog.actions.append(m_action) modlog.actions.append(m_action)
await modlog.commit() await modlog.save()
return return
modlog = await Setting.find_one(q(guild=ctx.guild.id, setting="modlog")) modlog = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "modlog")
if not modlog: if not modlog:
return return

View file

@ -1,22 +1,6 @@
"""Permissions wrappers.""" """Permissions wrappers."""
from interactions import InteractionContext, Permissions from interactions import InteractionContext, Permissions
from jarvis.config import JarvisConfig
def user_is_bot_admin() -> bool:
"""Check if a user is a JARVIS admin."""
async def predicate(ctx: InteractionContext) -> bool:
"""Command check predicate."""
cfg = JarvisConfig.from_yaml()
if getattr(cfg, "admins", None):
return ctx.author.id in cfg.admins
else:
return False
return predicate
def admin_or_permissions(*perms: list) -> bool: def admin_or_permissions(*perms: list) -> bool:
"""Check if a user is an admin or has other perms.""" """Check if a user is an admin or has other perms."""

564
poetry.lock generated
View file

@ -1,21 +1,22 @@
# This file is automatically @generated by Poetry and should not be changed by hand. # This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand.
[[package]] [[package]]
name = "aiofile" name = "aiofile"
version = "3.8.1" version = "3.8.5"
description = "Asynchronous file operations." description = "Asynchronous file operations."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7, <4" python-versions = ">=3.7, <4"
files = [ files = [
{file = "aiofile-3.8.1.tar.gz", hash = "sha256:1623b98d88fbd16bbd2808d010de4e185a700e950ed3f17455dd851aa2455f40"}, {file = "aiofile-3.8.5-py3-none-any.whl", hash = "sha256:6644b61ab143a8e516920cdb02d5b46f89c0a37ef036417720f653b5ed31a8c9"},
{file = "aiofile-3.8.5.tar.gz", hash = "sha256:bb1ca0b2c4ef3b78f5012a2a3919a4151f873b6aabdc73a7b9b8e94edb2e01ae"},
] ]
[package.dependencies] [package.dependencies]
caio = ">=0.9.0,<0.10.0" caio = ">=0.9.0,<0.10.0"
[package.extras] [package.extras]
develop = ["aiomisc", "pytest", "pytest-cov"] develop = ["aiomisc-pytest", "coveralls", "pytest", "pytest-cov", "pytest-rst"]
[[package]] [[package]]
name = "aiofiles" name = "aiofiles"
@ -341,14 +342,14 @@ toml = "*"
[[package]] [[package]]
name = "beautifulsoup4" name = "beautifulsoup4"
version = "4.11.2" version = "4.12.0"
description = "Screen-scraping library" description = "Screen-scraping library"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6.0" python-versions = ">=3.6.0"
files = [ files = [
{file = "beautifulsoup4-4.11.2-py3-none-any.whl", hash = "sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39"}, {file = "beautifulsoup4-4.12.0-py3-none-any.whl", hash = "sha256:2130a5ad7f513200fae61a17abb5e338ca980fa28c439c0571014bc0217e9591"},
{file = "beautifulsoup4-4.11.2.tar.gz", hash = "sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106"}, {file = "beautifulsoup4-4.12.0.tar.gz", hash = "sha256:c5fceeaec29d09c84970e47c65f2f0efe57872f7cff494c9691a26ec0ff13234"},
] ]
[package.dependencies] [package.dependencies]
@ -360,32 +361,46 @@ lxml = ["lxml"]
[[package]] [[package]]
name = "black" name = "black"
version = "22.12.0" version = "23.1.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, {file = "black-23.1.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221"},
{file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, {file = "black-23.1.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26"},
{file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, {file = "black-23.1.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b"},
{file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, {file = "black-23.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104"},
{file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, {file = "black-23.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074"},
{file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, {file = "black-23.1.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27"},
{file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, {file = "black-23.1.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648"},
{file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, {file = "black-23.1.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958"},
{file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, {file = "black-23.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a"},
{file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, {file = "black-23.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481"},
{file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, {file = "black-23.1.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad"},
{file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, {file = "black-23.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8"},
{file = "black-23.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24"},
{file = "black-23.1.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6"},
{file = "black-23.1.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd"},
{file = "black-23.1.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580"},
{file = "black-23.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468"},
{file = "black-23.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753"},
{file = "black-23.1.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651"},
{file = "black-23.1.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06"},
{file = "black-23.1.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739"},
{file = "black-23.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9"},
{file = "black-23.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555"},
{file = "black-23.1.0-py3-none-any.whl", hash = "sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32"},
{file = "black-23.1.0.tar.gz", hash = "sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac"},
] ]
[package.dependencies] [package.dependencies]
click = ">=8.0.0" click = ">=8.0.0"
mypy-extensions = ">=0.4.3" mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0" pathspec = ">=0.9.0"
platformdirs = ">=2" platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
colorama = ["colorama (>=0.4.3)"] colorama = ["colorama (>=0.4.3)"]
@ -625,14 +640,14 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
[[package]] [[package]]
name = "dateparser" name = "dateparser"
version = "1.1.7" version = "1.1.8"
description = "Date parsing library designed to parse dates from HTML pages" description = "Date parsing library designed to parse dates from HTML pages"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "dateparser-1.1.7-py2.py3-none-any.whl", hash = "sha256:fbed8b738a24c9cd7f47c4f2089527926566fe539e1a06125eddba75917b1eef"}, {file = "dateparser-1.1.8-py2.py3-none-any.whl", hash = "sha256:070b29b5bbf4b1ec2cd51c96ea040dc68a614de703910a91ad1abba18f9f379f"},
{file = "dateparser-1.1.7.tar.gz", hash = "sha256:ff047d9cffad4d3113ead8ec0faf8a7fc43bab7d853ac8715e071312b53c465a"}, {file = "dateparser-1.1.8.tar.gz", hash = "sha256:86b8b7517efcc558f085a142cdb7620f0921543fcabdb538c8a4c4001d8178e3"},
] ]
[package.dependencies] [package.dependencies]
@ -710,19 +725,19 @@ dev = ["coverage", "coveralls", "pytest"]
[[package]] [[package]]
name = "filelock" name = "filelock"
version = "3.10.0" version = "3.10.3"
description = "A platform independent file lock." description = "A platform independent file lock."
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "filelock-3.10.0-py3-none-any.whl", hash = "sha256:e90b34656470756edf8b19656785c5fea73afa1953f3e1b0d645cef11cab3182"}, {file = "filelock-3.10.3-py3-none-any.whl", hash = "sha256:99d6282f732410d44242ca02aa49835cf5473e2dd4d6734a2a785c8889dc191e"},
{file = "filelock-3.10.0.tar.gz", hash = "sha256:3199fd0d3faea8b911be52b663dfccceb84c95949dd13179aa21436d1a79c4ce"}, {file = "filelock-3.10.3.tar.gz", hash = "sha256:a26bfa34d26293e04886dff13fa8dd0c8c6e1a786b723c689755fe8939297410"},
] ]
[package.extras] [package.extras]
docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"]
testing = ["covdefaults (>=2.3)", "coverage (>=7.2.1)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.2.2)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"]
[[package]] [[package]]
name = "frozenlist" name = "frozenlist"
@ -840,14 +855,14 @@ gitdb = ">=4.0.1,<5"
[[package]] [[package]]
name = "identify" name = "identify"
version = "2.5.20" version = "2.5.21"
description = "File identification library for Python" description = "File identification library for Python"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "identify-2.5.20-py2.py3-none-any.whl", hash = "sha256:5dfef8a745ca4f2c95f27e9db74cb4c8b6d9916383988e8791f3595868f78a33"}, {file = "identify-2.5.21-py2.py3-none-any.whl", hash = "sha256:69edcaffa8e91ae0f77d397af60f148b6b45a8044b2cc6d99cafa5b04793ff00"},
{file = "identify-2.5.20.tar.gz", hash = "sha256:c8b288552bc5f05a08aff09af2f58e6976bf8ac87beb38498a0e3d98ba64eb18"}, {file = "identify-2.5.21.tar.gz", hash = "sha256:7671a05ef9cfaf8ff63b15d45a91a1147a03aaccb2976d4e9bd047cbbc508471"},
] ]
[package.extras] [package.extras]
@ -867,14 +882,14 @@ files = [
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "6.0.0" version = "6.1.0"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, {file = "importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"},
{file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, {file = "importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"},
] ]
[package.dependencies] [package.dependencies]
@ -891,32 +906,33 @@ version = "5.0.0"
description = "Easy, simple, scalable and modular: a Python API wrapper for interactions." description = "Easy, simple, scalable and modular: a Python API wrapper for interactions."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.10,<4.0" python-versions = ">=3.10"
files = [] files = []
develop = false develop = false
[package.dependencies] [package.dependencies]
aiohttp = "^3.8.3" aiohttp = "*"
attrs = ">=22.1.0" attrs = "*"
discord-typings = "^0.5.1" discord-typings = ">=0.5.1"
emoji = "^2.1.0" emoji = "*"
mypy = ">0.930" tomli = "*"
tomli = "^2.0.1"
[package.extras] [package.extras]
console = [] all = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aioconsole (>=0.6.0)", "aiodns", "faust-cchardet", "jurigged", "orjson", "sentry-sdk", "uvloop"]
docs = ["mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python"] console = ["aioconsole (>=0.6.0)"]
jurigged = [] dev = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aioconsole (>=0.6.0)", "aiodns", "faust-cchardet", "jurigged", "mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python", "orjson", "pre-commit", "pytest", "pytest-asyncio", "pytest-cov", "pytest-recording", "python-dotenv", "sentry-sdk", "typeguard", "uvloop"]
sentry = [] docs = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aioconsole (>=0.6.0)", "aiodns", "faust-cchardet", "jurigged", "mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python", "orjson", "sentry-sdk", "uvloop"]
jurigged = ["jurigged"]
sentry = ["sentry-sdk"]
speedup = ["Brotli", "aiodns", "faust-cchardet", "orjson", "uvloop"] speedup = ["Brotli", "aiodns", "faust-cchardet", "orjson", "uvloop"]
tests = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-recording", "python-dotenv", "typeguard"] tests = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-recording", "python-dotenv", "typeguard"]
voice = [] voice = ["PyNaCl (>=1.5.0,<1.6)"]
[package.source] [package.source]
type = "git" type = "git"
url = "https://github.com/interactions-py/interactions.py" url = "https://github.com/interactions-py/interactions.py"
reference = "5.x" reference = "5.x"
resolved_reference = "316388be6d608e12e64c93af2cc1b03fc0acfa97" resolved_reference = "dc2554a61387c953bcaad79a7166f93b98dd0eab"
[[package]] [[package]]
name = "jarvis-core" name = "jarvis-core"
@ -943,7 +959,7 @@ umongo = "^3.1.0"
type = "git" type = "git"
url = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git" url = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git"
reference = "main" reference = "main"
resolved_reference = "392797c4aea76db0dff8772d95acea3ff3094b46" resolved_reference = "ec4219e5a54bea78ff19f23f1754a036e8d0eae3"
[[package]] [[package]]
name = "jinxed" name = "jinxed"
@ -1240,58 +1256,11 @@ files = [
{file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
] ]
[[package]]
name = "mypy"
version = "1.1.1"
description = "Optional static typing for Python"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "mypy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39c7119335be05630611ee798cc982623b9e8f0cff04a0b48dfc26100e0b97af"},
{file = "mypy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61bf08362e93b6b12fad3eab68c4ea903a077b87c90ac06c11e3d7a09b56b9c1"},
{file = "mypy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb19c9f662e41e474e0cff502b7064a7edc6764f5262b6cd91d698163196799"},
{file = "mypy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:315ac73cc1cce4771c27d426b7ea558fb4e2836f89cb0296cbe056894e3a1f78"},
{file = "mypy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5cb14ff9919b7df3538590fc4d4c49a0f84392237cbf5f7a816b4161c061829e"},
{file = "mypy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26cdd6a22b9b40b2fd71881a8a4f34b4d7914c679f154f43385ca878a8297389"},
{file = "mypy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b5f81b40d94c785f288948c16e1f2da37203c6006546c5d947aab6f90aefef2"},
{file = "mypy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b437be1c02712a605591e1ed1d858aba681757a1e55fe678a15c2244cd68a5"},
{file = "mypy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d809f88734f44a0d44959d795b1e6f64b2bbe0ea4d9cc4776aa588bb4229fc1c"},
{file = "mypy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:a380c041db500e1410bb5b16b3c1c35e61e773a5c3517926b81dfdab7582be54"},
{file = "mypy-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7c7b708fe9a871a96626d61912e3f4ddd365bf7f39128362bc50cbd74a634d5"},
{file = "mypy-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c10fa12df1232c936830839e2e935d090fc9ee315744ac33b8a32216b93707"},
{file = "mypy-1.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0a28a76785bf57655a8ea5eb0540a15b0e781c807b5aa798bd463779988fa1d5"},
{file = "mypy-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ef6a01e563ec6a4940784c574d33f6ac1943864634517984471642908b30b6f7"},
{file = "mypy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d64c28e03ce40d5303450f547e07418c64c241669ab20610f273c9e6290b4b0b"},
{file = "mypy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64cc3afb3e9e71a79d06e3ed24bb508a6d66f782aff7e56f628bf35ba2e0ba51"},
{file = "mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"},
{file = "mypy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b0c373d071593deefbcdd87ec8db91ea13bd8f1328d44947e88beae21e8d5e9"},
{file = "mypy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2888ce4fe5aae5a673386fa232473014056967f3904f5abfcf6367b5af1f612a"},
{file = "mypy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ba15f9627a5723e522d007fe708007bae52b93faab00f95d72f03e1afa9598"},
{file = "mypy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:59bbd71e5c58eed2e992ce6523180e03c221dcd92b52f0e792f291d67b15a71c"},
{file = "mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"},
{file = "mypy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b398d8b1f4fba0e3c6463e02f8ad3346f71956b92287af22c9b12c3ec965a9f"},
{file = "mypy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:69b35d1dcb5707382810765ed34da9db47e7f95b3528334a3c999b0c90fe523f"},
{file = "mypy-1.1.1-py3-none-any.whl", hash = "sha256:4e4e8b362cdf99ba00c2b218036002bdcdf1e0de085cdb296a49df03fb31dfc4"},
{file = "mypy-1.1.1.tar.gz", hash = "sha256:ae9ceae0f5b9059f33dbc62dea087e942c0ccab4b7a003719cb70f9b8abfa32f"},
]
[package.dependencies]
mypy-extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = ">=3.10"
[package.extras]
dmypy = ["psutil (>=4.0)"]
install-types = ["pip"]
python2 = ["typed-ast (>=1.4.0,<2)"]
reports = ["lxml"]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker." description = "Type system extensions for programs checked with the mypy type checker."
category = "main" category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -1422,56 +1391,61 @@ numpy = [
[[package]] [[package]]
name = "orjson" name = "orjson"
version = "3.8.7" version = "3.8.8"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "orjson-3.8.7-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:f98c82850b7b4b7e27785ca43706fa86c893cdb88d54576bbb9b0d9c1070e421"}, {file = "orjson-3.8.8-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:18fcdea75d8b571dc9b185652b81397b62878ae7934fd62e6a0103a5b8448e34"},
{file = "orjson-3.8.7-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1dee503c6c1a0659c5b46f5f39d9ca9d3657b11ca8bb4af8506086df416887d9"}, {file = "orjson-3.8.8-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:306618884929b596e2e083f82b5617da812df25b0c467542371f1d51f0c5a6f5"},
{file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc4fa83831f42ce5c938f8cefc2e175fa1df6f661fdeaba3badf26d2b8cfcf73"}, {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edc65ddb6ae6f8fbb2bbf78ac98f75b729c9eeb0776d5508dd76d3a948dda1dd"},
{file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e432c6c9c8b97ad825276d5795286f7cc9689f377a97e3b7ecf14918413303f"}, {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e6a6d55e01bce74516dff15302627a13b1f4edcb1c3942dd660978dee423ccf2"},
{file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee519964a5a0efb9633f38b1129fd242807c5c57162844efeeaab1c8de080051"}, {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28075c4b502d792fb6703e983d456b2a30d5d6f332d26092eb312dc782e64c64"},
{file = "orjson-3.8.7-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:109b539ce5bf60a121454d008fa67c3b67e5a3249e47d277012645922cf74bd0"}, {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eda4c37e48ff549763183a1549c10eec6ea40439520b17d09359cd74a425069"},
{file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ad4d441fbde4133af6fee37f67dbf23181b9c537ecc317346ec8c3b4c8ec7705"}, {file = "orjson-3.8.8-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a3eac485a15493164867729f44e1e1247b3094ff19d37708e8cdc9c88a93c623"},
{file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:89dc786419e1ce2588345f58dd6a434e6728bce66b94989644234bcdbe39b603"}, {file = "orjson-3.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:88bf40e5468444c04374d1b8f1877cebbaef6bb7406cb6b4a34a570c5cbb87bc"},
{file = "orjson-3.8.7-cp310-none-win_amd64.whl", hash = "sha256:697abde7350fb8076d44bcb6b4ab3ce415ae2b5a9bb91efc460e5ab0d96bb5d3"}, {file = "orjson-3.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:747bd4e09d8aa61e1ff677a7dd1cffd28a5d13c22f3769123c58ec988bf1b83d"},
{file = "orjson-3.8.7-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:1c19f47b35b9966a3abadf341b18ee4a860431bf2b00fd8d58906d51cf78aa70"}, {file = "orjson-3.8.8-cp310-none-win_amd64.whl", hash = "sha256:dd7d86c5f5f820ac9d4783477e86eb984b63bdb32359935609eb33cf65049c54"},
{file = "orjson-3.8.7-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3ffaabb380cd0ee187b4fc362516df6bf739808130b1339445c7d8878fca36e7"}, {file = "orjson-3.8.8-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:52293a6097750c2d434737966fe6e2a1ed489ac70cc8e584f5944af83de0b787"},
{file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d88837002c5a8af970745b8e0ca1b0fdb06aafbe7f1279e110d338ea19f3d23"}, {file = "orjson-3.8.8-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9322450f392dceb49810d2f820b1932af22d66f67f1d45c31f160067dd06359f"},
{file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff60187d1b7e0bfab376b6002b08c560b7de06c87cf3a8ac639ecf58f84c5f3b"}, {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68d59e3ae84a9b6f14b45a89f7fde4a08a87ea5eb76bfc854b354640de8156f5"},
{file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0110970aed35dec293f30ed1e09f8604afd5d15c5ef83de7f6c427619b3ba47b"}, {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:022347dad2253081eaa25366834bb8b06a5aceb0e83b39c6b0aa865759e49d69"},
{file = "orjson-3.8.7-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:51b275475d4e36118b65ad56f9764056a09d985c5d72e64579bf8816f1356a5e"}, {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddfcc54793e266056fe1c257d0804c336bca1c5c1ee7979d674e1fc19cfb0a6a"},
{file = "orjson-3.8.7-cp311-none-win_amd64.whl", hash = "sha256:63144d27735f3b60f079f247ac9a289d80dfe49a7f03880dfa0c0ba64d6491d5"}, {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:449d8ed1e0e6b24e9df5a06b59fd66ea7f7293e141257069601ae8ff9fad705c"},
{file = "orjson-3.8.7-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a16273d77db746bb1789a2bbfded81148a60743fd6f9d5185e02d92e3732fa18"}, {file = "orjson-3.8.8-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0204bc414bc6f7a595211569840b422d96649fd8686efa1fbbcb12eed5dd9521"},
{file = "orjson-3.8.7-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:5bb32259ea22cc9dd47a6fdc4b8f9f1e2f798fcf56c7c1122a7df0f4c5d33bf3"}, {file = "orjson-3.8.8-cp311-none-win_amd64.whl", hash = "sha256:e991a5c2c5f2f299c77e1d07ef2812ff5b68e1d97a2aab01aca29cf756473aa3"},
{file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad02e9102d4ba67db30a136e631e32aeebd1dce26c9f5942a457b02df131c5d0"}, {file = "orjson-3.8.8-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:2006d9c046bbf335c951f61e016a27bd4f17323dd116f601e4a8a11739cd0a62"},
{file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dbcfcec2b7ac52deb7be3685b551addc28ee8fa454ef41f8b714df6ba0e32a27"}, {file = "orjson-3.8.8-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4553d85bad4cbd634a40b7b5d36daaa197a6025f9ce3e2165b371e528759093d"},
{file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a0e5504a5fc86083cc210c6946e8d61e13fe9f1d7a7bf81b42f7050a49d4fb"}, {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57ee45d2cc6c11c50afb5a0c09d7cd559aea76c77250dbe996be6a03464d4a50"},
{file = "orjson-3.8.7-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:7bd4fd37adb03b1f2a1012d43c9f95973a02164e131dfe3ff804d7e180af5653"}, {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:02f5b5db1e424706eb9f70f1c25699ff4cef16fadfc64af5b70f8628eafe4771"},
{file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:188ed9f9a781333ad802af54c55d5a48991e292239aef41bd663b6e314377eb8"}, {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d7c9f3b1598a1ccd806ef02257a76a00c7ede09662ddb54eec2b4bd92874254"},
{file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cc52f58c688cb10afd810280e450f56fbcb27f52c053463e625c8335c95db0dc"}, {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90d171932b6a9d50e79fa2762cb303e3556bbf25c08bb316fe346ec58af9c19"},
{file = "orjson-3.8.7-cp37-none-win_amd64.whl", hash = "sha256:403c8c84ac8a02c40613b0493b74d5256379e65196d39399edbf2ed3169cbeb5"}, {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:28dfe774c345130f1117c4d023644ec52d9d50e3eaadb9bd1c668d91dc109bb5"},
{file = "orjson-3.8.7-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:7d6ac5f8a2a17095cd927c4d52abbb38af45918e0d3abd60fb50cfd49d71ae24"}, {file = "orjson-3.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8f84116fcc3714e7ba3cbeb1b11ac5e4549e7d2726c50142f8299fff9dea7d53"},
{file = "orjson-3.8.7-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:0295a7bfd713fa89231fd0822c995c31fc2343c59a1d13aa1b8b6651335654f5"}, {file = "orjson-3.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f989f8580db86166aaaa938ccd1597ba1817e3f5df14c047baafe783e3d24173"},
{file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feb32aaaa34cf2f891eb793ad320d4bb6731328496ae59b6c9eb1b620c42b529"}, {file = "orjson-3.8.8-cp37-none-win_amd64.whl", hash = "sha256:66045850f286090800a18662d81d44f88c3fcb60ea3a9947d5caeab5d1efc92e"},
{file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7a3ab1a473894e609b6f1d763838c6689ba2b97620c256a32c4d9f10595ac179"}, {file = "orjson-3.8.8-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:2c2c5f3d3bbd61dba646e2b9c54a0dd7941b03fba49726bd31c1c23fedf0b9aa"},
{file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e8c430d82b532c5ab95634e034bbf6ca7432ffe175a3e63eadd493e00b3a555"}, {file = "orjson-3.8.8-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9cb36d4a14f3a911369219d5abc19b907bc41ed2730f7bfe0847b0fd3e834c87"},
{file = "orjson-3.8.7-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:366cc75f7e09106f9dac95a675aef413367b284f25507d21e55bd7f45f445e80"}, {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:343124f84da0a33c83ee106a98b3e3c42767c88323d4a2809683cbe83816e8be"},
{file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:84d154d07e8b17d97e990d5d710b719a031738eb1687d8a05b9089f0564ff3e0"}, {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24ad122d8dd057acf2a9965a2ffc1bc12fb310ae1cfe2912db930cbb9ef7eaba"},
{file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06180014afcfdc167ca984b312218aa62ce20093965c437c5f9166764cb65ef7"}, {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2f28a92a9bcb4e8635524b20db1b539bda8613872f306b36cdfd9d3577d03ac"},
{file = "orjson-3.8.7-cp38-none-win_amd64.whl", hash = "sha256:41244431ba13f2e6ef22b52c5cf0202d17954489f4a3c0505bd28d0e805c3546"}, {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81d3c5b253eebfc4a61cea1f255a576cb2b889afa99f4510f30ec13201d4f457"},
{file = "orjson-3.8.7-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:b20f29fa8371b8023f1791df035a2c3ccbd98baa429ac3114fc104768f7db6f8"}, {file = "orjson-3.8.8-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:317164f7d4c0540a6eb8b0a0faeec84ef011d359da05188423db762b65f84e1d"},
{file = "orjson-3.8.7-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:226bfc1da2f21ee74918cee2873ea9a0fec1a8830e533cb287d192d593e99d02"}, {file = "orjson-3.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5e7e39357371d4ae5649f33c01886508a4c8e5fa5c7344554af041dc0f004c01"},
{file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75c11023ac29e29fd3e75038d0e8dd93f9ea24d7b9a5e871967a8921a88df24"}, {file = "orjson-3.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:60fefd4bbd796b4296f478e705fe2c2c7defd28da98d3017743eb87c3238a380"},
{file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78604d3acfd7cd502f6381eea0c42281fe2b74755b334074ab3ebc0224100be1"}, {file = "orjson-3.8.8-cp38-none-win_amd64.whl", hash = "sha256:0dc4a52f1087baeec6b58248fd6b01f17c124fb99f6f770596851ea434a7be0b"},
{file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7129a6847f0494aa1427167486ef6aea2e835ba05f6c627df522692ee228f65"}, {file = "orjson-3.8.8-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6bcb449537a99f55c5f05187bac00b4549a795e89c10dcca0d7629548852357"},
{file = "orjson-3.8.7-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1a1a8f4980059f48483782c608145b0f74538c266e01c183d9bcd9f8b71dbada"}, {file = "orjson-3.8.8-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9c98dc791aa44268ba7f6e21124cf885c813b155316c6bf257560571d243fe15"},
{file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d60304172a33705ce4bd25a6261ab84bed2dab0b3d3b79672ea16c7648af4832"}, {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b2abf93b727a6af7c5ec8816168cbdff39c716af18ced425dd50ae46d69765c"},
{file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4f733062d84389c32c0492e5a4929056fac217034a94523debe0430bcc602cda"}, {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23447d38375a19d57975d4e32d9ce9f533803c197fd4292e10d3234c052037a8"},
{file = "orjson-3.8.7-cp39-none-win_amd64.whl", hash = "sha256:010e2970ec9e826c332819e0da4b14b29b19641da0f1a6af4cec91629ef9b988"}, {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c2e19d2b46cc93c7218bf8180807bf922ff61dc9883458a06edc66d22970fff"},
{file = "orjson-3.8.7.tar.gz", hash = "sha256:8460c8810652dba59c38c80d27c325b5092d189308d8d4f3e688dbd8d4f3b2dc"}, {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e480d74d7bf415e6548a364669404119a85dbe0e3c6cd5f7cb4c7003eac20164"},
{file = "orjson-3.8.8-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8e0bff5656b99dd975cae2e5230b39e5909d06c0692fd1f6f06dc46f1fe705d0"},
{file = "orjson-3.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:56bb6eb7a254eec3b15feba9b20f4172ccbe6ea50a54cf66cbc8e1e4a19585c2"},
{file = "orjson-3.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1af1cfad5d90b68e15fd625c889c4f9f91d7a88f49512cdb89f01c3881e0c9d9"},
{file = "orjson-3.8.8-cp39-none-win_amd64.whl", hash = "sha256:d5514dfe200356a1d5a6039e00dca78d87d063f3da1eb6a371253e5a8b7ab5b0"},
{file = "orjson-3.8.8.tar.gz", hash = "sha256:c096d7a523bae6ffb9c4a228ba4691d66113f0f2231579dc945523fbef09c6da"},
] ]
[[package]] [[package]]
@ -1774,48 +1748,48 @@ files = [
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "1.10.6" version = "1.10.7"
description = "Data validation and settings management using python type hints" description = "Data validation and settings management using python type hints"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "pydantic-1.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9289065611c48147c1dd1fd344e9d57ab45f1d99b0fb26c51f1cf72cd9bcd31"}, {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"},
{file = "pydantic-1.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c32b6bba301490d9bb2bf5f631907803135e8085b6aa3e5fe5a770d46dd0160"}, {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"},
{file = "pydantic-1.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd9b9e98068fa1068edfc9eabde70a7132017bdd4f362f8b4fd0abed79c33083"}, {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"},
{file = "pydantic-1.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c84583b9df62522829cbc46e2b22e0ec11445625b5acd70c5681ce09c9b11c4"}, {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"},
{file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b41822064585fea56d0116aa431fbd5137ce69dfe837b599e310034171996084"}, {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"},
{file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61f1f08adfaa9cc02e0cbc94f478140385cbd52d5b3c5a657c2fceb15de8d1fb"}, {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"},
{file = "pydantic-1.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:32937835e525d92c98a1512218db4eed9ddc8f4ee2a78382d77f54341972c0e7"}, {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"},
{file = "pydantic-1.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd5c531b22928e63d0cb1868dee76123456e1de2f1cb45879e9e7a3f3f1779b"}, {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"},
{file = "pydantic-1.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e277bd18339177daa62a294256869bbe84df1fb592be2716ec62627bb8d7c81d"}, {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"},
{file = "pydantic-1.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f15277d720aa57e173954d237628a8d304896364b9de745dcb722f584812c7"}, {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"},
{file = "pydantic-1.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b243b564cea2576725e77aeeda54e3e0229a168bc587d536cd69941e6797543d"}, {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"},
{file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3ce13a558b484c9ae48a6a7c184b1ba0e5588c5525482681db418268e5f86186"}, {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"},
{file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ac1cd4deed871dfe0c5f63721e29debf03e2deefa41b3ed5eb5f5df287c7b70"}, {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"},
{file = "pydantic-1.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:b1eb6610330a1dfba9ce142ada792f26bbef1255b75f538196a39e9e90388bf4"}, {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"},
{file = "pydantic-1.10.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ca83739c1263a044ec8b79df4eefc34bbac87191f0a513d00dd47d46e307a65"}, {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"},
{file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea4e2a7cb409951988e79a469f609bba998a576e6d7b9791ae5d1e0619e1c0f2"}, {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"},
{file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53de12b4608290992a943801d7756f18a37b7aee284b9ffa794ee8ea8153f8e2"}, {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"},
{file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:60184e80aac3b56933c71c48d6181e630b0fbc61ae455a63322a66a23c14731a"}, {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"},
{file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:415a3f719ce518e95a92effc7ee30118a25c3d032455d13e121e3840985f2efd"}, {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"},
{file = "pydantic-1.10.6-cp37-cp37m-win_amd64.whl", hash = "sha256:72cb30894a34d3a7ab6d959b45a70abac8a2a93b6480fc5a7bfbd9c935bdc4fb"}, {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"},
{file = "pydantic-1.10.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3091d2eaeda25391405e36c2fc2ed102b48bac4b384d42b2267310abae350ca6"}, {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"},
{file = "pydantic-1.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:751f008cd2afe812a781fd6aa2fb66c620ca2e1a13b6a2152b1ad51553cb4b77"}, {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"},
{file = "pydantic-1.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12e837fd320dd30bd625be1b101e3b62edc096a49835392dcf418f1a5ac2b832"}, {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"},
{file = "pydantic-1.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d92831d0115874d766b1f5fddcdde0c5b6c60f8c6111a394078ec227fca6d"}, {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"},
{file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:476f6674303ae7965730a382a8e8d7fae18b8004b7b69a56c3d8fa93968aa21c"}, {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"},
{file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3a2be0a0f32c83265fd71a45027201e1278beaa82ea88ea5b345eea6afa9ac7f"}, {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"},
{file = "pydantic-1.10.6-cp38-cp38-win_amd64.whl", hash = "sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35"}, {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"},
{file = "pydantic-1.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6195ca908045054dd2d57eb9c39a5fe86409968b8040de8c2240186da0769da7"}, {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"},
{file = "pydantic-1.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43cdeca8d30de9a897440e3fb8866f827c4c31f6c73838e3a01a14b03b067b1d"}, {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"},
{file = "pydantic-1.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c19eb5163167489cb1e0161ae9220dadd4fc609a42649e7e84a8fa8fff7a80f"}, {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"},
{file = "pydantic-1.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62"}, {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"},
{file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:528dcf7ec49fb5a84bf6fe346c1cc3c55b0e7603c2123881996ca3ad79db5bfc"}, {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"},
{file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:163e79386c3547c49366e959d01e37fc30252285a70619ffc1b10ede4758250a"}, {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"},
{file = "pydantic-1.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:189318051c3d57821f7233ecc94708767dd67687a614a4e8f92b4a020d4ffd06"}, {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"},
{file = "pydantic-1.10.6-py3-none-any.whl", hash = "sha256:acc6783751ac9c9bc4680379edd6d286468a1dc8d7d9906cd6f1186ed682b2b0"}, {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"},
{file = "pydantic-1.10.6.tar.gz", hash = "sha256:cf95adb0d1671fc38d8c43dd921ad5814a735e7d9b4d9e437c088002863854fd"}, {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"},
] ]
[package.dependencies] [package.dependencies]
@ -2214,18 +2188,18 @@ full = ["numpy"]
[[package]] [[package]]
name = "redis" name = "redis"
version = "4.5.1" version = "4.5.3"
description = "Python client for Redis database and key-value store" description = "Python client for Redis database and key-value store"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "redis-4.5.1-py3-none-any.whl", hash = "sha256:5deb072d26e67d2be1712603bfb7947ec3431fb0eec9c578994052e33035af6d"}, {file = "redis-4.5.3-py3-none-any.whl", hash = "sha256:7df17a0a2b72a4c8895b462dd07616c51b1dcb48fdd7ecb7b6f4bf39ecb2e94e"},
{file = "redis-4.5.1.tar.gz", hash = "sha256:1eec3741cda408d3a5f84b78d089c8b8d895f21b3b050988351e925faf202864"}, {file = "redis-4.5.3.tar.gz", hash = "sha256:56732e156fe31801c4f43396bd3ca0c2a7f6f83d7936798531b9848d103381aa"},
] ]
[package.dependencies] [package.dependencies]
async-timeout = ">=4.0.2" async-timeout = {version = ">=4.0.2", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
hiredis = ["hiredis (>=1.0.0)"] hiredis = ["hiredis (>=1.0.0)"]
@ -2233,100 +2207,72 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
[[package]] [[package]]
name = "regex" name = "regex"
version = "2022.10.31" version = "2023.3.23"
description = "Alternative regular expression module, to replace re." description = "Alternative regular expression module, to replace re."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.8"
files = [ files = [
{file = "regex-2022.10.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8ff454ef0bb061e37df03557afda9d785c905dab15584860f982e88be73015f"}, {file = "regex-2023.3.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:845a5e2d84389c4ddada1a9b95c055320070f18bb76512608374aca00d22eca8"},
{file = "regex-2022.10.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1eba476b1b242620c266edf6325b443a2e22b633217a9835a52d8da2b5c051f9"}, {file = "regex-2023.3.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:87d9951f5a538dd1d016bdc0dcae59241d15fa94860964833a54d18197fcd134"},
{file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0e5af9a9effb88535a472e19169e09ce750c3d442fb222254a276d77808620b"}, {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37ae17d3be44c0b3f782c28ae9edd8b47c1f1776d4cabe87edc0b98e1f12b021"},
{file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d03fe67b2325cb3f09be029fd5da8df9e6974f0cde2c2ac6a79d2634e791dd57"}, {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b8eb1e3bca6b48dc721818a60ae83b8264d4089a4a41d62be6d05316ec38e15"},
{file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9d0b68ac1743964755ae2d89772c7e6fb0118acd4d0b7464eaf3921c6b49dd4"}, {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df45fac182ebc3c494460c644e853515cc24f5ad9da05f8ffb91da891bfee879"},
{file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a45b6514861916c429e6059a55cf7db74670eaed2052a648e3e4d04f070e001"}, {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7006105b10b59971d3b248ad75acc3651c7e4cf54d81694df5a5130a3c3f7ea"},
{file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b0886885f7323beea6f552c28bff62cbe0983b9fbb94126531693ea6c5ebb90"}, {file = "regex-2023.3.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93f3f1aa608380fe294aa4cb82e2afda07a7598e828d0341e124b8fd9327c715"},
{file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5aefb84a301327ad115e9d346c8e2760009131d9d4b4c6b213648d02e2abe144"}, {file = "regex-2023.3.23-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787954f541ab95d8195d97b0b8cf1dc304424adb1e07365967e656b92b38a699"},
{file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:702d8fc6f25bbf412ee706bd73019da5e44a8400861dfff7ff31eb5b4a1276dc"}, {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:20abe0bdf03630fe92ccafc45a599bca8b3501f48d1de4f7d121153350a2f77d"},
{file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a3c1ebd4ed8e76e886507c9eddb1a891673686c813adf889b864a17fafcf6d66"}, {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11d00c31aeab9a6e0503bc77e73ed9f4527b3984279d997eb145d7c7be6268fd"},
{file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:50921c140561d3db2ab9f5b11c5184846cde686bb5a9dc64cae442926e86f3af"}, {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d5bbe0e1511b844794a3be43d6c145001626ba9a6c1db8f84bdc724e91131d9d"},
{file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7db345956ecce0c99b97b042b4ca7326feeec6b75facd8390af73b18e2650ffc"}, {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ea3c0cb56eadbf4ab2277e7a095676370b3e46dbfc74d5c383bd87b0d6317910"},
{file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:763b64853b0a8f4f9cfb41a76a4a85a9bcda7fdda5cb057016e7706fde928e66"}, {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d895b4c863059a4934d3e874b90998df774644a41b349ebb330f85f11b4ef2c0"},
{file = "regex-2022.10.31-cp310-cp310-win32.whl", hash = "sha256:44136355e2f5e06bf6b23d337a75386371ba742ffa771440b85bed367c1318d1"}, {file = "regex-2023.3.23-cp310-cp310-win32.whl", hash = "sha256:9d764514d19b4edcc75fd8cb1423448ef393e8b6cbd94f38cab983ab1b75855d"},
{file = "regex-2022.10.31-cp310-cp310-win_amd64.whl", hash = "sha256:bfff48c7bd23c6e2aec6454aaf6edc44444b229e94743b34bdcdda2e35126cf5"}, {file = "regex-2023.3.23-cp310-cp310-win_amd64.whl", hash = "sha256:11d1f2b7a0696dc0310de0efb51b1f4d813ad4401fe368e83c0c62f344429f98"},
{file = "regex-2022.10.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b4b1fe58cd102d75ef0552cf17242705ce0759f9695334a56644ad2d83903fe"}, {file = "regex-2023.3.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8a9c63cde0eaa345795c0fdeb19dc62d22e378c50b0bc67bf4667cd5b482d98b"},
{file = "regex-2022.10.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:542e3e306d1669b25936b64917285cdffcd4f5c6f0247636fec037187bd93542"}, {file = "regex-2023.3.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dd7200b4c27b68cf9c9646da01647141c6db09f48cc5b51bc588deaf8e98a797"},
{file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c27cc1e4b197092e50ddbf0118c788d9977f3f8f35bfbbd3e76c1846a3443df7"}, {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22720024b90a6ba673a725dcc62e10fb1111b889305d7c6b887ac7466b74bedb"},
{file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8e38472739028e5f2c3a4aded0ab7eadc447f0d84f310c7a8bb697ec417229e"}, {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b190a339090e6af25f4a5fd9e77591f6d911cc7b96ecbb2114890b061be0ac1"},
{file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76c598ca73ec73a2f568e2a72ba46c3b6c8690ad9a07092b18e48ceb936e9f0c"}, {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e76b6fc0d8e9efa39100369a9b3379ce35e20f6c75365653cf58d282ad290f6f"},
{file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c28d3309ebd6d6b2cf82969b5179bed5fefe6142c70f354ece94324fa11bf6a1"}, {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7868b8f218bf69a2a15402fde08b08712213a1f4b85a156d90473a6fb6b12b09"},
{file = "regex-2022.10.31-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9af69f6746120998cd9c355e9c3c6aec7dff70d47247188feb4f829502be8ab4"}, {file = "regex-2023.3.23-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2472428efc4127374f494e570e36b30bb5e6b37d9a754f7667f7073e43b0abdd"},
{file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a5f9505efd574d1e5b4a76ac9dd92a12acb2b309551e9aa874c13c11caefbe4f"}, {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c37df2a060cb476d94c047b18572ee2b37c31f831df126c0da3cd9227b39253d"},
{file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5ff525698de226c0ca743bfa71fc6b378cda2ddcf0d22d7c37b1cc925c9650a5"}, {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4479f9e2abc03362df4045b1332d4a2b7885b245a30d4f4b051c4083b97d95d8"},
{file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe7fda2fe7c8890d454f2cbc91d6c01baf206fbc96d89a80241a02985118c0c"}, {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e2396e0678167f2d0c197da942b0b3fb48fee2f0b5915a0feb84d11b6686afe6"},
{file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2cdc55ca07b4e70dda898d2ab7150ecf17c990076d3acd7a5f3b25cb23a69f1c"}, {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75f288c60232a5339e0ff2fa05779a5e9c74e9fc085c81e931d4a264501e745b"},
{file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:44a6c2f6374e0033873e9ed577a54a3602b4f609867794c1a3ebba65e4c93ee7"}, {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c869260aa62cee21c5eb171a466c0572b5e809213612ef8d495268cd2e34f20d"},
{file = "regex-2022.10.31-cp311-cp311-win32.whl", hash = "sha256:d8716f82502997b3d0895d1c64c3b834181b1eaca28f3f6336a71777e437c2af"}, {file = "regex-2023.3.23-cp311-cp311-win32.whl", hash = "sha256:25f0532fd0c53e96bad84664171969de9673b4131f2297f1db850d3918d58858"},
{file = "regex-2022.10.31-cp311-cp311-win_amd64.whl", hash = "sha256:61edbca89aa3f5ef7ecac8c23d975fe7261c12665f1d90a6b1af527bba86ce61"}, {file = "regex-2023.3.23-cp311-cp311-win_amd64.whl", hash = "sha256:5ccfafd98473e007cebf7da10c1411035b7844f0f204015efd050601906dbb53"},
{file = "regex-2022.10.31-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a069c8483466806ab94ea9068c34b200b8bfc66b6762f45a831c4baaa9e8cdd"}, {file = "regex-2023.3.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6572ff287176c0fb96568adb292674b421fa762153ed074d94b1d939ed92c253"},
{file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d26166acf62f731f50bdd885b04b38828436d74e8e362bfcb8df221d868b5d9b"}, {file = "regex-2023.3.23-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a610e0adfcb0fc84ea25f6ea685e39e74cbcd9245a72a9a7aab85ff755a5ed27"},
{file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac741bf78b9bb432e2d314439275235f41656e189856b11fb4e774d9f7246d81"}, {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086afe222d58b88b62847bdbd92079b4699350b4acab892f88a935db5707c790"},
{file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75f591b2055523fc02a4bbe598aa867df9e953255f0b7f7715d2a36a9c30065c"}, {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79e29fd62fa2f597a6754b247356bda14b866131a22444d67f907d6d341e10f3"},
{file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bddd61d2a3261f025ad0f9ee2586988c6a00c780a2fb0a92cea2aa702c54"}, {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c07ce8e9eee878a48ebeb32ee661b49504b85e164b05bebf25420705709fdd31"},
{file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef4163770525257876f10e8ece1cf25b71468316f61451ded1a6f44273eedeb5"}, {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b036f401895e854de9fefe061518e78d506d8a919cc250dc3416bca03f6f9a"},
{file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7b280948d00bd3973c1998f92e22aa3ecb76682e3a4255f33e1020bd32adf443"}, {file = "regex-2023.3.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78ac8dd8e18800bb1f97aad0d73f68916592dddf233b99d2b5cabc562088503a"},
{file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d0213671691e341f6849bf33cd9fad21f7b1cb88b89e024f33370733fec58742"}, {file = "regex-2023.3.23-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:539dd010dc35af935b32f248099e38447bbffc10b59c2b542bceead2bed5c325"},
{file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:22e7ebc231d28393dfdc19b185d97e14a0f178bedd78e85aad660e93b646604e"}, {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9bf4a5626f2a0ea006bf81e8963f498a57a47d58907eaa58f4b3e13be68759d8"},
{file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8ad241da7fac963d7573cc67a064c57c58766b62a9a20c452ca1f21050868dfa"}, {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf86b4328c204c3f315074a61bc1c06f8a75a8e102359f18ce99fbcbbf1951f0"},
{file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:586b36ebda81e6c1a9c5a5d0bfdc236399ba6595e1397842fd4a45648c30f35e"}, {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2848bf76673c83314068241c8d5b7fa9ad9bed866c979875a0e84039349e8fa7"},
{file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0653d012b3bf45f194e5e6a41df9258811ac8fc395579fa82958a8b76286bea4"}, {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c125a02d22c555e68f7433bac8449992fa1cead525399f14e47c2d98f2f0e467"},
{file = "regex-2022.10.31-cp36-cp36m-win32.whl", hash = "sha256:144486e029793a733e43b2e37df16a16df4ceb62102636ff3db6033994711066"}, {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cd1671e9d5ac05ce6aa86874dd8dfa048824d1dbe73060851b310c6c1a201a96"},
{file = "regex-2022.10.31-cp36-cp36m-win_amd64.whl", hash = "sha256:c14b63c9d7bab795d17392c7c1f9aaabbffd4cf4387725a0ac69109fb3b550c6"}, {file = "regex-2023.3.23-cp38-cp38-win32.whl", hash = "sha256:fffe57312a358be6ec6baeb43d253c36e5790e436b7bf5b7a38df360363e88e9"},
{file = "regex-2022.10.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4cac3405d8dda8bc6ed499557625585544dd5cbf32072dcc72b5a176cb1271c8"}, {file = "regex-2023.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:dbb3f87e15d3dd76996d604af8678316ad2d7d20faa394e92d9394dfd621fd0c"},
{file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23cbb932cc53a86ebde0fb72e7e645f9a5eec1a5af7aa9ce333e46286caef783"}, {file = "regex-2023.3.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c88e8c226473b5549fe9616980ea7ca09289246cfbdf469241edf4741a620004"},
{file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74bcab50a13960f2a610cdcd066e25f1fd59e23b69637c92ad470784a51b1347"}, {file = "regex-2023.3.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6560776ec19c83f3645bbc5db64a7a5816c9d8fb7ed7201c5bcd269323d88072"},
{file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d680ef3e4d405f36f0d6d1ea54e740366f061645930072d39bca16a10d8c93"}, {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b1fc2632c01f42e06173d8dd9bb2e74ab9b0afa1d698058c867288d2c7a31f3"},
{file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6910b56b700bea7be82c54ddf2e0ed792a577dfaa4a76b9af07d550af435c6"}, {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdf7ad455f1916b8ea5cdbc482d379f6daf93f3867b4232d14699867a5a13af7"},
{file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:659175b2144d199560d99a8d13b2228b85e6019b6e09e556209dfb8c37b78a11"}, {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fc33b27b1d800fc5b78d7f7d0f287e35079ecabe68e83d46930cf45690e1c8c"},
{file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1ddf14031a3882f684b8642cb74eea3af93a2be68893901b2b387c5fd92a03ec"}, {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c49552dc938e3588f63f8a78c86f3c9c75301e813bca0bef13bdb4b87ccf364"},
{file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b683e5fd7f74fb66e89a1ed16076dbab3f8e9f34c18b1979ded614fe10cdc4d9"}, {file = "regex-2023.3.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e152461e9a0aedec7d37fc66ec0fa635eca984777d3d3c3e36f53bf3d3ceb16e"},
{file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2bde29cc44fa81c0a0c8686992c3080b37c488df167a371500b2a43ce9f026d1"}, {file = "regex-2023.3.23-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:db034255e72d2995cf581b14bb3fc9c00bdbe6822b49fcd4eef79e1d5f232618"},
{file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4919899577ba37f505aaebdf6e7dc812d55e8f097331312db7f1aab18767cce8"}, {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:55ae114da21b7a790b90255ea52d2aa3a0d121a646deb2d3c6a3194e722fc762"},
{file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:9c94f7cc91ab16b36ba5ce476f1904c91d6c92441f01cd61a8e2729442d6fcf5"}, {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ef3f528fe1cc3d139508fe1b22523745aa77b9d6cb5b0bf277f48788ee0b993f"},
{file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae1e96785696b543394a4e3f15f3f225d44f3c55dafe3f206493031419fedf95"}, {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:a81c9ec59ca2303acd1ccd7b9ac409f1e478e40e96f8f79b943be476c5fdb8bb"},
{file = "regex-2022.10.31-cp37-cp37m-win32.whl", hash = "sha256:c670f4773f2f6f1957ff8a3962c7dd12e4be54d05839b216cb7fd70b5a1df394"}, {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cde09c4fdd070772aa2596d97e942eb775a478b32459e042e1be71b739d08b77"},
{file = "regex-2022.10.31-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0caeff18b96ea90fc0eb6e3bdb2b10ab5b01a95128dfeccb64a7238decf5f0"}, {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3cd9f5dd7b821f141d3a6ca0d5d9359b9221e4f051ca3139320adea9f1679691"},
{file = "regex-2022.10.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:131d4be09bea7ce2577f9623e415cab287a3c8e0624f778c1d955ec7c281bd4d"}, {file = "regex-2023.3.23-cp39-cp39-win32.whl", hash = "sha256:7304863f3a652dab5e68e6fb1725d05ebab36ec0390676d1736e0571ebb713ef"},
{file = "regex-2022.10.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e613a98ead2005c4ce037c7b061f2409a1a4e45099edb0ef3200ee26ed2a69a8"}, {file = "regex-2023.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:54c3fa855a3f7438149de3211738dd9b5f0c733f48b54ae05aa7fce83d48d858"},
{file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052b670fafbe30966bbe5d025e90b2a491f85dfe5b2583a163b5e60a85a321ad"}, {file = "regex-2023.3.23.tar.gz", hash = "sha256:dc80df325b43ffea5cdea2e3eaa97a44f3dd298262b1c7fe9dbb2a9522b956a7"},
{file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa62a07ac93b7cb6b7d0389d8ef57ffc321d78f60c037b19dfa78d6b17c928ee"},
{file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5352bea8a8f84b89d45ccc503f390a6be77917932b1c98c4cdc3565137acc714"},
{file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20f61c9944f0be2dc2b75689ba409938c14876c19d02f7585af4460b6a21403e"},
{file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29c04741b9ae13d1e94cf93fca257730b97ce6ea64cfe1eba11cf9ac4e85afb6"},
{file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:543883e3496c8b6d58bd036c99486c3c8387c2fc01f7a342b760c1ea3158a318"},
{file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7a8b43ee64ca8f4befa2bea4083f7c52c92864d8518244bfa6e88c751fa8fff"},
{file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6a9a19bea8495bb419dc5d38c4519567781cd8d571c72efc6aa959473d10221a"},
{file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6ffd55b5aedc6f25fd8d9f905c9376ca44fcf768673ffb9d160dd6f409bfda73"},
{file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4bdd56ee719a8f751cf5a593476a441c4e56c9b64dc1f0f30902858c4ef8771d"},
{file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ca88da1bd78990b536c4a7765f719803eb4f8f9971cc22d6ca965c10a7f2c4c"},
{file = "regex-2022.10.31-cp38-cp38-win32.whl", hash = "sha256:5a260758454580f11dd8743fa98319bb046037dfab4f7828008909d0aa5292bc"},
{file = "regex-2022.10.31-cp38-cp38-win_amd64.whl", hash = "sha256:5e6a5567078b3eaed93558842346c9d678e116ab0135e22eb72db8325e90b453"},
{file = "regex-2022.10.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5217c25229b6a85049416a5c1e6451e9060a1edcf988641e309dbe3ab26d3e49"},
{file = "regex-2022.10.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bf41b8b0a80708f7e0384519795e80dcb44d7199a35d52c15cc674d10b3081b"},
{file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf0da36a212978be2c2e2e2d04bdff46f850108fccc1851332bcae51c8907cc"},
{file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d403d781b0e06d2922435ce3b8d2376579f0c217ae491e273bab8d092727d244"},
{file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a37d51fa9a00d265cf73f3de3930fa9c41548177ba4f0faf76e61d512c774690"},
{file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4f781ffedd17b0b834c8731b75cce2639d5a8afe961c1e58ee7f1f20b3af185"},
{file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d243b36fbf3d73c25e48014961e83c19c9cc92530516ce3c43050ea6276a2ab7"},
{file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:370f6e97d02bf2dd20d7468ce4f38e173a124e769762d00beadec3bc2f4b3bc4"},
{file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:597f899f4ed42a38df7b0e46714880fb4e19a25c2f66e5c908805466721760f5"},
{file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7dbdce0c534bbf52274b94768b3498abdf675a691fec5f751b6057b3030f34c1"},
{file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:22960019a842777a9fa5134c2364efaed5fbf9610ddc5c904bd3a400973b0eb8"},
{file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7f5a3ffc731494f1a57bd91c47dc483a1e10048131ffb52d901bfe2beb6102e8"},
{file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7ef6b5942e6bfc5706301a18a62300c60db9af7f6368042227ccb7eeb22d0892"},
{file = "regex-2022.10.31-cp39-cp39-win32.whl", hash = "sha256:395161bbdbd04a8333b9ff9763a05e9ceb4fe210e3c7690f5e68cedd3d65d8e1"},
{file = "regex-2022.10.31-cp39-cp39-win_amd64.whl", hash = "sha256:957403a978e10fb3ca42572a23e6f7badff39aa1ce2f4ade68ee452dc6807692"},
{file = "regex-2022.10.31.tar.gz", hash = "sha256:a3a98921da9a1bf8457aeee6a551948a83601689e5ecdd736894ea9bbec77e83"},
] ]
[[package]] [[package]]
@ -2475,7 +2421,7 @@ interactions = {git = "https://github.com/interactions-py/interactions.py", rev
type = "git" type = "git"
url = "https://github.com/zevaryx/statipy" url = "https://github.com/zevaryx/statipy"
reference = "main" reference = "main"
resolved_reference = "b73d7812e29e2dc8290b869bc94b029c7c1ec3e9" resolved_reference = "9bc2f910dafd7702d275185a8b96187c6ab1f8fb"
[[package]] [[package]]
name = "thefuzz" name = "thefuzz"
@ -2594,14 +2540,14 @@ files = [
[[package]] [[package]]
name = "tzlocal" name = "tzlocal"
version = "4.2" version = "4.3"
description = "tzinfo object for the local timezone" description = "tzinfo object for the local timezone"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
files = [ files = [
{file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"}, {file = "tzlocal-4.3-py3-none-any.whl", hash = "sha256:b44c4388f3d34f25862cfbb387578a4d70fec417649da694a132f628a23367e2"},
{file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"}, {file = "tzlocal-4.3.tar.gz", hash = "sha256:3f21d09e1b2aa9f2dacca12da240ca37de3ba5237a93addfd6d593afe9073355"},
] ]
[package.dependencies] [package.dependencies]
@ -2609,8 +2555,7 @@ pytz-deprecation-shim = "*"
tzdata = {version = "*", markers = "platform_system == \"Windows\""} tzdata = {version = "*", markers = "platform_system == \"Windows\""}
[package.extras] [package.extras]
devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"] devenv = ["black", "check-manifest", "flake8", "pyroma", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"]
test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"]
[[package]] [[package]]
name = "ulid-py" name = "ulid-py"
@ -2705,40 +2650,39 @@ test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess
[[package]] [[package]]
name = "watchdog" name = "watchdog"
version = "2.3.1" version = "3.0.0"
description = "Filesystem events monitoring" description = "Filesystem events monitoring"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
files = [ files = [
{file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1f1200d4ec53b88bf04ab636f9133cb703eb19768a39351cee649de21a33697"}, {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"},
{file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:564e7739abd4bd348aeafbf71cc006b6c0ccda3160c7053c4a53b67d14091d42"}, {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"},
{file = "watchdog-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95ad708a9454050a46f741ba5e2f3468655ea22da1114e4c40b8cbdaca572565"}, {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"},
{file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a073c91a6ef0dda488087669586768195c3080c66866144880f03445ca23ef16"}, {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"},
{file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa8b028750b43e80eea9946d01925168eeadb488dfdef1d82be4b1e28067f375"}, {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"},
{file = "watchdog-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:964fd236cd443933268ae49b59706569c8b741073dbfd7ca705492bae9d39aab"}, {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"},
{file = "watchdog-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:91fd146d723392b3e6eb1ac21f122fcce149a194a2ba0a82c5e4d0ee29cd954c"}, {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"},
{file = "watchdog-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f"}, {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"},
{file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85bf2263290591b7c5fa01140601b64c831be88084de41efbcba6ea289874f44"}, {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"},
{file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f2df370cd8e4e18499dd0bfdef476431bcc396108b97195d9448d90924e3131"}, {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"},
{file = "watchdog-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b"}, {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"},
{file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f5d0f7eac86807275eba40b577c671b306f6f335ba63a5c5a348da151aba0fc"}, {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"},
{file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b848c71ef2b15d0ef02f69da8cc120d335cec0ed82a3fa7779e27a5a8527225"}, {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"},
{file = "watchdog-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d9878be36d2b9271e3abaa6f4f051b363ff54dbbe7e7df1af3c920e4311ee43"}, {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"},
{file = "watchdog-2.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cd61f98cb37143206818cb1786d2438626aa78d682a8f2ecee239055a9771d5"}, {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"},
{file = "watchdog-2.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d2dbcf1acd96e7a9c9aefed201c47c8e311075105d94ce5e899f118155709fd"}, {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"},
{file = "watchdog-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03f342a9432fe08107defbe8e405a2cb922c5d00c4c6c168c68b633c64ce6190"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7a596f9415a378d0339681efc08d2249e48975daae391d58f2e22a3673b977cf"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:0e1dd6d449267cc7d6935d7fe27ee0426af6ee16578eed93bacb1be9ff824d2d"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_i686.whl", hash = "sha256:7a1876f660e32027a1a46f8a0fa5747ad4fcf86cb451860eae61a26e102c8c79"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:2caf77ae137935c1466f8cefd4a3aec7017b6969f425d086e6a528241cba7256"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:53f3e95081280898d9e4fc51c5c69017715929e4eea1ab45801d5e903dd518ad"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:9da7acb9af7e4a272089bd2af0171d23e0d6271385c51d4d9bde91fe918c53ed"}, {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8a4d484e846dcd75e96b96d80d80445302621be40e293bfdf34a631cab3b33dc"}, {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"},
{file = "watchdog-2.3.1-py3-none-win32.whl", hash = "sha256:a74155398434937ac2780fd257c045954de5b11b5c52fc844e2199ce3eecf4cf"}, {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"},
{file = "watchdog-2.3.1-py3-none-win_amd64.whl", hash = "sha256:5defe4f0918a2a1a4afbe4dbb967f743ac3a93d546ea4674567806375b024adb"}, {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"},
{file = "watchdog-2.3.1-py3-none-win_ia64.whl", hash = "sha256:4109cccf214b7e3462e8403ab1e5b17b302ecce6c103eb2fc3afa534a7f27b96"}, {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"},
{file = "watchdog-2.3.1.tar.gz", hash = "sha256:d9f9ed26ed22a9d331820a8432c3680707ea8b54121ddcc9dc7d9f2ceeb36906"},
] ]
[package.extras] [package.extras]
@ -2942,4 +2886,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.10,<4" python-versions = ">=3.10,<4"
content-hash = "973d2a4a3018b5b46a43a44e3d7f3c05b80b5b03a67cc77ccb75bb10194ff646" content-hash = "a557982b4ff57231c0e25cf53e760e49173fae268fb840e891ff4fe78436d3be"

View file

@ -31,6 +31,8 @@ redis = "^4.4.0"
interactions = {git = "https://github.com/interactions-py/interactions.py", rev = "5.x"} interactions = {git = "https://github.com/interactions-py/interactions.py", rev = "5.x"}
statipy = {git = "https://github.com/zevaryx/statipy", rev = "main"} statipy = {git = "https://github.com/zevaryx/statipy", rev = "main"}
beanie = "^1.17.0" beanie = "^1.17.0"
pydantic = "^1.10.7"
orjson = "^3.8.8"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = {version = "^22.3.0", allow-prereleases = true} black = {version = "^22.3.0", allow-prereleases = true}
@ -38,6 +40,7 @@ black = {version = "^22.3.0", allow-prereleases = true}
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pre-commit = "^2.21.0" pre-commit = "^2.21.0"
pandas = "^1.5.3" pandas = "^1.5.3"
black = "^23.1.0"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]