Merge branch 'precommit' into 'main'
`pre-commit` for J.A.R.V.I.S. See merge request stark-industries/j.a.r.v.i.s.!27
This commit is contained in:
commit
84ec50791a
53 changed files with 1003 additions and 1250 deletions
|
@ -35,9 +35,3 @@ repos:
|
||||||
- flake8-bandit~=2.1
|
- flake8-bandit~=2.1
|
||||||
- flake8-docstrings~=1.5
|
- flake8-docstrings~=1.5
|
||||||
args: [--max-line-length=120, --ignore=ANN101 D107 ANN102 ANN206 D105 ANN204]
|
args: [--max-line-length=120, --ignore=ANN101 D107 ANN102 ANN206 D105 ANN204]
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
||||||
rev: v0.910
|
|
||||||
hooks:
|
|
||||||
- id: mypy
|
|
||||||
args: [--install-types, --non-interactive]
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
"""Main J.A.R.V.I.S. package."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union
|
from typing import Optional
|
||||||
|
|
||||||
from discord import Intents
|
from discord import Intents
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
@ -9,9 +11,21 @@ from discord_slash import SlashCommand
|
||||||
from mongoengine import connect
|
from mongoengine import connect
|
||||||
from psutil import Process
|
from psutil import Process
|
||||||
|
|
||||||
from jarvis import logo, tasks, utils
|
from jarvis import logo # noqa: F401
|
||||||
|
from jarvis import tasks
|
||||||
|
from jarvis import utils
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
from jarvis.events import guild, member, message
|
from jarvis.events import guild
|
||||||
|
from jarvis.events import member
|
||||||
|
from jarvis.events import message
|
||||||
|
|
||||||
|
jconfig = get_config()
|
||||||
|
|
||||||
|
logger = logging.getLogger("discord")
|
||||||
|
logger.setLevel(logging.getLevelName(jconfig.log_level))
|
||||||
|
file_handler = logging.FileHandler(filename="jarvis.log", encoding="UTF-8", mode="w")
|
||||||
|
file_handler.setFormatter(logging.Formatter("[%(asctime)s][%(levelname)s][%(name)s] %(message)s"))
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
if asyncio.get_event_loop().is_closed():
|
if asyncio.get_event_loop().is_closed():
|
||||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||||
|
@ -20,7 +34,6 @@ intents = Intents.default()
|
||||||
intents.members = True
|
intents.members = True
|
||||||
restart_ctx = None
|
restart_ctx = None
|
||||||
|
|
||||||
jconfig = get_config()
|
|
||||||
|
|
||||||
jarvis = commands.Bot(
|
jarvis = commands.Bot(
|
||||||
command_prefix=utils.get_prefix,
|
command_prefix=utils.get_prefix,
|
||||||
|
@ -31,11 +44,12 @@ jarvis = commands.Bot(
|
||||||
|
|
||||||
slash = SlashCommand(jarvis, sync_commands=True, sync_on_cog_reload=True)
|
slash = SlashCommand(jarvis, sync_commands=True, sync_on_cog_reload=True)
|
||||||
jarvis_self = Process()
|
jarvis_self = Process()
|
||||||
__version__ = "1.10.3"
|
__version__ = "1.10.4"
|
||||||
|
|
||||||
|
|
||||||
@jarvis.event
|
@jarvis.event
|
||||||
async def on_ready():
|
async def on_ready() -> None:
|
||||||
|
"""d.py on_ready override."""
|
||||||
global restart_ctx
|
global restart_ctx
|
||||||
print(" Logged in as {0.user}".format(jarvis))
|
print(" Logged in as {0.user}".format(jarvis))
|
||||||
print(" Connected to {} guild(s)".format(len(jarvis.guilds)))
|
print(" Connected to {} guild(s)".format(len(jarvis.guilds)))
|
||||||
|
@ -47,9 +61,7 @@ async def on_ready():
|
||||||
if "guild" in restart_ctx:
|
if "guild" in restart_ctx:
|
||||||
guild = find(lambda x: x.id == restart_ctx["guild"], jarvis.guilds)
|
guild = find(lambda x: x.id == restart_ctx["guild"], jarvis.guilds)
|
||||||
if guild:
|
if guild:
|
||||||
channel = find(
|
channel = find(lambda x: x.id == restart_ctx["channel"], guild.channels)
|
||||||
lambda x: x.id == restart_ctx["channel"], guild.channels
|
|
||||||
)
|
|
||||||
elif "user" in restart_ctx:
|
elif "user" in restart_ctx:
|
||||||
channel = jarvis.get_user(restart_ctx["user"])
|
channel = jarvis.get_user(restart_ctx["user"])
|
||||||
if channel:
|
if channel:
|
||||||
|
@ -57,7 +69,8 @@ async def on_ready():
|
||||||
restart_ctx = None
|
restart_ctx = None
|
||||||
|
|
||||||
|
|
||||||
def run(ctx=None):
|
def run(ctx: dict = None) -> Optional[dict]:
|
||||||
|
"""Run J.A.R.V.I.S."""
|
||||||
global restart_ctx
|
global restart_ctx
|
||||||
if ctx:
|
if ctx:
|
||||||
restart_ctx = ctx
|
restart_ctx = ctx
|
||||||
|
@ -78,9 +91,7 @@ def run(ctx=None):
|
||||||
jarvis.load_extension(extension)
|
jarvis.load_extension(extension)
|
||||||
print(
|
print(
|
||||||
" https://discord.com/api/oauth2/authorize?client_id="
|
" https://discord.com/api/oauth2/authorize?client_id="
|
||||||
+ "{}&permissions=8&scope=bot%20applications.commands".format(
|
+ "{}&permissions=8&scope=bot%20applications.commands".format(jconfig.client_id) # noqa: W503
|
||||||
jconfig.client_id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
jarvis.max_messages = jconfig.max_messages
|
jarvis.max_messages = jconfig.max_messages
|
||||||
|
@ -88,7 +99,7 @@ def run(ctx=None):
|
||||||
|
|
||||||
# Add event listeners
|
# Add event listeners
|
||||||
if jconfig.events:
|
if jconfig.events:
|
||||||
listeners = [
|
_ = [
|
||||||
guild.GuildEventHandler(jarvis),
|
guild.GuildEventHandler(jarvis),
|
||||||
member.MemberEventHandler(jarvis),
|
member.MemberEventHandler(jarvis),
|
||||||
message.MessageEventHandler(jarvis),
|
message.MessageEventHandler(jarvis),
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
from jarvis.cogs.admin import (
|
"""J.A.R.V.I.S. Admin Cogs."""
|
||||||
ban,
|
from discord.ext.commands import Bot
|
||||||
kick,
|
|
||||||
lock,
|
from jarvis.cogs.admin import ban
|
||||||
lockdown,
|
from jarvis.cogs.admin import kick
|
||||||
mute,
|
from jarvis.cogs.admin import lock
|
||||||
purge,
|
from jarvis.cogs.admin import lockdown
|
||||||
roleping,
|
from jarvis.cogs.admin import mute
|
||||||
warning,
|
from jarvis.cogs.admin import purge
|
||||||
)
|
from jarvis.cogs.admin import roleping
|
||||||
|
from jarvis.cogs.admin import warning
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: Bot) -> None:
|
||||||
|
"""Add admin cogs to J.A.R.V.I.S."""
|
||||||
bot.add_cog(ban.BanCog(bot))
|
bot.add_cog(ban.BanCog(bot))
|
||||||
bot.add_cog(kick.KickCog(bot))
|
bot.add_cog(kick.KickCog(bot))
|
||||||
bot.add_cog(lock.LockCog(bot))
|
bot.add_cog(lock.LockCog(bot))
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
|
"""J.A.R.V.I.S. BanCog."""
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from ButtonPaginator import Paginator
|
from ButtonPaginator import Paginator
|
||||||
from discord import User
|
from discord import User
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.model import ButtonStyle
|
from discord_slash.model import ButtonStyle
|
||||||
from discord_slash.utils.manage_commands import create_choice, create_option
|
from discord_slash.utils.manage_commands import create_choice
|
||||||
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Ban, Unban
|
from jarvis.db.models import Ban
|
||||||
|
from jarvis.db.models import Unban
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
from jarvis.utils.cachecog import CacheCog
|
from jarvis.utils.cachecog import CacheCog
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
@ -17,6 +22,8 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class BanCog(CacheCog):
|
class BanCog(CacheCog):
|
||||||
|
"""J.A.R.V.I.S. BanCog."""
|
||||||
|
|
||||||
def __init__(self, bot: commands.Bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
|
|
||||||
|
@ -28,7 +35,8 @@ class BanCog(CacheCog):
|
||||||
duration: int,
|
duration: int,
|
||||||
active: bool,
|
active: bool,
|
||||||
fields: list,
|
fields: list,
|
||||||
):
|
) -> None:
|
||||||
|
"""Apply a Discord ban."""
|
||||||
await ctx.guild.ban(user, reason=reason)
|
await ctx.guild.ban(user, reason=reason)
|
||||||
_ = Ban(
|
_ = Ban(
|
||||||
user=user.id,
|
user=user.id,
|
||||||
|
@ -57,9 +65,8 @@ class BanCog(CacheCog):
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
async def discord_apply_unban(
|
async def discord_apply_unban(self, ctx: SlashContext, user: User, reason: str) -> None:
|
||||||
self, ctx: SlashContext, user: User, reason: str
|
"""Apply a Discord unban."""
|
||||||
):
|
|
||||||
await ctx.guild.unban(user, reason=reason)
|
await ctx.guild.unban(user, reason=reason)
|
||||||
_ = Unban(
|
_ = Unban(
|
||||||
user=user.id,
|
user=user.id,
|
||||||
|
@ -126,7 +133,7 @@ class BanCog(CacheCog):
|
||||||
reason: str = None,
|
reason: str = None,
|
||||||
type: str = "perm",
|
type: str = "perm",
|
||||||
duration: int = 4,
|
duration: int = 4,
|
||||||
):
|
) -> None:
|
||||||
if not user or user == ctx.author:
|
if not user or user == ctx.author:
|
||||||
await ctx.send("You cannot ban yourself.", hidden=True)
|
await ctx.send("You cannot ban yourself.", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -134,22 +141,16 @@ class BanCog(CacheCog):
|
||||||
await ctx.send("I'm afraid I can't let you do that", hidden=True)
|
await ctx.send("I'm afraid I can't let you do that", hidden=True)
|
||||||
return
|
return
|
||||||
if type == "temp" and duration < 0:
|
if type == "temp" and duration < 0:
|
||||||
await ctx.send(
|
await ctx.send("You cannot set a temp ban to < 0 hours.", hidden=True)
|
||||||
"You cannot set a temp ban to < 0 hours.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
elif type == "temp" and duration > 744:
|
elif type == "temp" and duration > 744:
|
||||||
await ctx.send(
|
await ctx.send("You cannot set a temp ban to > 1 month", hidden=True)
|
||||||
"You cannot set a temp ban to > 1 month", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
if len(reason) > 100:
|
if len(reason) > 100:
|
||||||
await ctx.send("Reason must be < 100 characters", hidden=True)
|
await ctx.send("Reason must be < 100 characters", hidden=True)
|
||||||
return
|
return
|
||||||
if not reason:
|
if not reason:
|
||||||
reason = (
|
reason = "Mr. Stark is displeased with your presence. Please leave."
|
||||||
"Mr. Stark is displeased with your presence. Please leave."
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
|
|
||||||
|
@ -158,10 +159,7 @@ class BanCog(CacheCog):
|
||||||
mtype = "perma"
|
mtype = "perma"
|
||||||
|
|
||||||
guild_name = ctx.guild.name
|
guild_name = ctx.guild.name
|
||||||
user_message = (
|
user_message = f"You have been {mtype}banned from {guild_name}." + f" Reason:\n{reason}"
|
||||||
f"You have been {mtype}banned from {guild_name}."
|
|
||||||
+ f" Reason:\n{reason}"
|
|
||||||
)
|
|
||||||
if mtype == "temp":
|
if mtype == "temp":
|
||||||
user_message += f"\nDuration: {duration} hours"
|
user_message += f"\nDuration: {duration} hours"
|
||||||
|
|
||||||
|
@ -202,9 +200,7 @@ class BanCog(CacheCog):
|
||||||
if type == "soft":
|
if type == "soft":
|
||||||
active = False
|
active = False
|
||||||
|
|
||||||
await self.discord_apply_ban(
|
await self.discord_apply_ban(ctx, reason, user, duration, active, fields)
|
||||||
ctx, reason, user, duration, active, fields
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
name="unban",
|
name="unban",
|
||||||
|
@ -230,7 +226,7 @@ class BanCog(CacheCog):
|
||||||
ctx: SlashContext,
|
ctx: SlashContext,
|
||||||
user: str,
|
user: str,
|
||||||
reason: str,
|
reason: str,
|
||||||
):
|
) -> None:
|
||||||
if len(reason) > 100:
|
if len(reason) > 100:
|
||||||
await ctx.send("Reason must be < 100 characters", hidden=True)
|
await ctx.send("Reason must be < 100 characters", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -251,29 +247,18 @@ class BanCog(CacheCog):
|
||||||
user, discrim = user.split("#")
|
user, discrim = user.split("#")
|
||||||
if discrim:
|
if discrim:
|
||||||
discord_ban_info = find(
|
discord_ban_info = find(
|
||||||
lambda x: x.user.name == user
|
lambda x: x.user.name == user and x.user.discriminator == discrim,
|
||||||
and x.user.discriminator == discrim,
|
|
||||||
bans,
|
bans,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
results = [
|
results = [x for x in filter(lambda x: x.user.name == user, bans)]
|
||||||
x for x in filter(lambda x: x.user.name == user, bans)
|
|
||||||
]
|
|
||||||
if results:
|
if results:
|
||||||
if len(results) > 1:
|
if len(results) > 1:
|
||||||
active_bans = []
|
active_bans = []
|
||||||
for ban in bans:
|
for ban in bans:
|
||||||
active_bans.append(
|
active_bans.append("{0} ({1}): {2}".format(ban.user.name, ban.user.id, ban.reason))
|
||||||
"{0} ({1}): {2}".format(
|
ab_message = "\n".join(active_bans)
|
||||||
ban.user.name, ban.user.id, ban.reason
|
message = f"More than one result. Please use one of the following IDs:\n```{ab_message}\n```"
|
||||||
)
|
|
||||||
)
|
|
||||||
message = (
|
|
||||||
"More than one result. "
|
|
||||||
+ "Please use one of the following IDs:\n```"
|
|
||||||
+ "\n".join(active_bans)
|
|
||||||
+ "\n```"
|
|
||||||
)
|
|
||||||
await ctx.send(message)
|
await ctx.send(message)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -284,9 +269,7 @@ class BanCog(CacheCog):
|
||||||
# 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, int):
|
if isinstance(user, int):
|
||||||
database_ban_info = Ban.objects(
|
database_ban_info = Ban.objects(guild=ctx.guild.id, user=user, active=True).first()
|
||||||
guild=ctx.guild.id, user=user, active=True
|
|
||||||
).first()
|
|
||||||
else:
|
else:
|
||||||
search = {
|
search = {
|
||||||
"guild": ctx.guild.id,
|
"guild": ctx.guild.id,
|
||||||
|
@ -303,13 +286,9 @@ class BanCog(CacheCog):
|
||||||
elif discord_ban_info:
|
elif discord_ban_info:
|
||||||
await self.discord_apply_unban(ctx, discord_ban_info.user, reason)
|
await self.discord_apply_unban(ctx, discord_ban_info.user, reason)
|
||||||
else:
|
else:
|
||||||
discord_ban_info = find(
|
discord_ban_info = find(lambda x: x.user.id == database_ban_info["id"], bans)
|
||||||
lambda x: x.user.id == database_ban_info["id"], bans
|
|
||||||
)
|
|
||||||
if discord_ban_info:
|
if discord_ban_info:
|
||||||
await self.discord_apply_unban(
|
await self.discord_apply_unban(ctx, discord_ban_info.user, reason)
|
||||||
ctx, discord_ban_info.user, reason
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
database_ban_info.active = False
|
database_ban_info.active = False
|
||||||
database_ban_info.save()
|
database_ban_info.save()
|
||||||
|
@ -321,10 +300,7 @@ class BanCog(CacheCog):
|
||||||
admin=ctx.author.id,
|
admin=ctx.author.id,
|
||||||
reason=reason,
|
reason=reason,
|
||||||
).save()
|
).save()
|
||||||
await ctx.send(
|
await ctx.send("Unable to find user in Discord, " + "but removed entry from database.")
|
||||||
"Unable to find user in Discord, "
|
|
||||||
+ "but removed entry from database."
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="bans",
|
base="bans",
|
||||||
|
@ -356,16 +332,13 @@ class BanCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(ban_members=True)
|
@admin_or_permissions(ban_members=True)
|
||||||
async def _bans_list(
|
async def _bans_list(self, ctx: SlashContext, type: int = 0, active: int = 1) -> None:
|
||||||
self, ctx: SlashContext, type: int = 0, active: int = 1
|
|
||||||
):
|
|
||||||
active = bool(active)
|
active = bool(active)
|
||||||
exists = self.check_cache(ctx, type=type, active=active)
|
exists = self.check_cache(ctx, type=type, active=active)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -385,10 +358,12 @@ class BanCog(CacheCog):
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name=f"Username: {ban.username}#{ban.discrim}",
|
name=f"Username: {ban.username}#{ban.discrim}",
|
||||||
value=f"Date: {ban.created_at.strftime('%d-%m-%Y')}\n"
|
value=(
|
||||||
+ f"User ID: {ban.user}\n"
|
f"Date: {ban.created_at.strftime('%d-%m-%Y')}\n"
|
||||||
+ f"Reason: {ban.reason}\n"
|
f"User ID: {ban.user}\n"
|
||||||
+ f"Type: {ban.type}\n\u200b",
|
f"Reason: {ban.reason}\n"
|
||||||
|
f"Type: {ban.type}\n\u200b"
|
||||||
|
),
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -399,12 +374,13 @@ class BanCog(CacheCog):
|
||||||
if ban.user.id not in db_bans:
|
if ban.user.id not in db_bans:
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name=f"Username: {ban.user.name}#"
|
name=f"Username: {ban.user.name}#" + f"{ban.user.discriminator}",
|
||||||
+ f"{ban.user.discriminator}",
|
value=(
|
||||||
value="Date: [unknown]\n"
|
f"Date: [unknown]\n"
|
||||||
+ f"User ID: {ban.user.id}\n"
|
f"User ID: {ban.user.id}\n"
|
||||||
+ f"Reason: {ban.reason}\n"
|
f"Reason: {ban.reason}\n"
|
||||||
+ "Type: manual\n\u200b",
|
"Type: manual\n\u200b"
|
||||||
|
),
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -426,9 +402,7 @@ class BanCog(CacheCog):
|
||||||
pages.append(embed)
|
pages.append(embed)
|
||||||
else:
|
else:
|
||||||
for i in range(0, len(bans), 5):
|
for i in range(0, len(bans), 5):
|
||||||
embed = build_embed(
|
embed = build_embed(title=title, description="", fields=fields[i : i + 5]) # noqa: E203
|
||||||
title=title, description="", fields=fields[i : i + 5]
|
|
||||||
)
|
|
||||||
embed.set_thumbnail(url=ctx.guild.icon_url)
|
embed.set_thumbnail(url=ctx.guild.icon_url)
|
||||||
pages.append(embed)
|
pages.append(embed)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
"""J.A.R.V.I.S. KickCog."""
|
||||||
from discord import User
|
from discord import User
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord.ext.commands import Bot
|
||||||
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Kick
|
from jarvis.db.models import Kick
|
||||||
|
@ -10,7 +13,9 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class KickCog(CacheCog):
|
class KickCog(CacheCog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. KickCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -32,7 +37,7 @@ class KickCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(kick_members=True)
|
@admin_or_permissions(kick_members=True)
|
||||||
async def _kick(self, ctx: SlashContext, user: User, reason=None):
|
async def _kick(self, ctx: SlashContext, user: User, reason: str = None) -> None:
|
||||||
if not user or user == ctx.author:
|
if not user or user == ctx.author:
|
||||||
await ctx.send("You cannot kick yourself.", hidden=True)
|
await ctx.send("You cannot kick yourself.", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -43,9 +48,7 @@ class KickCog(CacheCog):
|
||||||
await ctx.send("Reason must be < 100 characters", hidden=True)
|
await ctx.send("Reason must be < 100 characters", hidden=True)
|
||||||
return
|
return
|
||||||
if not reason:
|
if not reason:
|
||||||
reason = (
|
reason = "Mr. Stark is displeased with your presence. Please leave."
|
||||||
"Mr. Stark is displeased with your presence. Please leave."
|
|
||||||
)
|
|
||||||
guild_name = ctx.guild.name
|
guild_name = ctx.guild.name
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title=f"You have been kicked from {guild_name}",
|
title=f"You have been kicked from {guild_name}",
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
|
"""J.A.R.V.I.S. LockCog."""
|
||||||
|
from contextlib import suppress
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from discord import Role, TextChannel, User, VoiceChannel
|
from discord import Role
|
||||||
from discord.ext import commands
|
from discord import TextChannel
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord import User
|
||||||
|
from discord import VoiceChannel
|
||||||
|
from discord.ext.commands import Bot
|
||||||
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Lock
|
from jarvis.db.models import Lock
|
||||||
|
@ -11,7 +17,9 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class LockCog(CacheCog):
|
class LockCog(CacheCog):
|
||||||
def __init__(self, bot: commands.Bot):
|
"""J.A.R.V.I.S. LockCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
|
|
||||||
async def _lock_channel(
|
async def _lock_channel(
|
||||||
|
@ -20,8 +28,8 @@ class LockCog(CacheCog):
|
||||||
role: Role,
|
role: Role,
|
||||||
admin: User,
|
admin: User,
|
||||||
reason: str,
|
reason: str,
|
||||||
allow_send=False,
|
allow_send: bool = False,
|
||||||
):
|
) -> None:
|
||||||
overrides = channel.overwrites_for(role)
|
overrides = channel.overwrites_for(role)
|
||||||
if isinstance(channel, TextChannel):
|
if isinstance(channel, TextChannel):
|
||||||
overrides.send_messages = allow_send
|
overrides.send_messages = allow_send
|
||||||
|
@ -34,7 +42,7 @@ class LockCog(CacheCog):
|
||||||
channel: Union[TextChannel, VoiceChannel],
|
channel: Union[TextChannel, VoiceChannel],
|
||||||
role: Role,
|
role: Role,
|
||||||
admin: User,
|
admin: User,
|
||||||
):
|
) -> None:
|
||||||
overrides = channel.overwrites_for(role)
|
overrides = channel.overwrites_for(role)
|
||||||
if isinstance(channel, TextChannel):
|
if isinstance(channel, TextChannel):
|
||||||
overrides.send_messages = None
|
overrides.send_messages = None
|
||||||
|
@ -73,7 +81,7 @@ class LockCog(CacheCog):
|
||||||
reason: str,
|
reason: str,
|
||||||
duration: int = 10,
|
duration: int = 10,
|
||||||
channel: Union[TextChannel, VoiceChannel] = None,
|
channel: Union[TextChannel, VoiceChannel] = None,
|
||||||
):
|
) -> None:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
if duration <= 0:
|
if duration <= 0:
|
||||||
await ctx.send("Duration must be > 0", hidden=True)
|
await ctx.send("Duration must be > 0", hidden=True)
|
||||||
|
@ -87,10 +95,8 @@ class LockCog(CacheCog):
|
||||||
if not channel:
|
if not channel:
|
||||||
channel = ctx.channel
|
channel = ctx.channel
|
||||||
for role in ctx.guild.roles:
|
for role in ctx.guild.roles:
|
||||||
try:
|
with suppress(Exception):
|
||||||
await self._lock_channel(channel, role, ctx.author, reason)
|
await self._lock_channel(channel, role, ctx.author, reason)
|
||||||
except Exception:
|
|
||||||
continue # Just continue on error
|
|
||||||
_ = Lock(
|
_ = Lock(
|
||||||
channel=channel.id,
|
channel=channel.id,
|
||||||
guild=ctx.guild.id,
|
guild=ctx.guild.id,
|
||||||
|
@ -117,20 +123,16 @@ class LockCog(CacheCog):
|
||||||
self,
|
self,
|
||||||
ctx: SlashContext,
|
ctx: SlashContext,
|
||||||
channel: Union[TextChannel, VoiceChannel] = None,
|
channel: Union[TextChannel, VoiceChannel] = None,
|
||||||
):
|
) -> None:
|
||||||
if not channel:
|
if not channel:
|
||||||
channel = ctx.channel
|
channel = ctx.channel
|
||||||
lock = Lock.objects(
|
lock = Lock.objects(guild=ctx.guild.id, channel=channel.id, active=True).first()
|
||||||
guild=ctx.guild.id, channel=channel.id, active=True
|
|
||||||
).first()
|
|
||||||
if not lock:
|
if not lock:
|
||||||
await ctx.send(f"{channel.mention} not locked.", hidden=True)
|
await ctx.send(f"{channel.mention} not locked.", hidden=True)
|
||||||
return
|
return
|
||||||
for role in ctx.guild.roles:
|
for role in ctx.guild.roles:
|
||||||
try:
|
with suppress(Exception):
|
||||||
await self._unlock_channel(channel, role, ctx.author)
|
await self._unlock_channel(channel, role, ctx.author)
|
||||||
except Exception:
|
|
||||||
continue # Just continue on error
|
|
||||||
lock.active = False
|
lock.active = False
|
||||||
lock.save()
|
lock.save()
|
||||||
await ctx.send(f"{channel.mention} unlocked")
|
await ctx.send(f"{channel.mention} unlocked")
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
"""J.A.R.V.I.S. LockdownCog."""
|
||||||
|
from contextlib import suppress
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Lock
|
from jarvis.db.models import Lock
|
||||||
|
@ -10,6 +13,8 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class LockdownCog(CacheCog):
|
class LockdownCog(CacheCog):
|
||||||
|
"""J.A.R.V.I.S. LockdownCog."""
|
||||||
|
|
||||||
def __init__(self, bot: commands.Bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
|
|
||||||
|
@ -38,7 +43,7 @@ class LockdownCog(CacheCog):
|
||||||
ctx: SlashContext,
|
ctx: SlashContext,
|
||||||
reason: str,
|
reason: str,
|
||||||
duration: int = 10,
|
duration: int = 10,
|
||||||
):
|
) -> None:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
if duration <= 0:
|
if duration <= 0:
|
||||||
await ctx.send("Duration must be > 0", hidden=True)
|
await ctx.send("Duration must be > 0", hidden=True)
|
||||||
|
@ -51,10 +56,8 @@ class LockdownCog(CacheCog):
|
||||||
updates = []
|
updates = []
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
for role in roles:
|
for role in roles:
|
||||||
try:
|
with suppress(Exception):
|
||||||
await self._lock_channel(channel, role, ctx.author, reason)
|
await self._lock_channel(channel, role, ctx.author, reason)
|
||||||
except Exception:
|
|
||||||
continue # Just continue on error
|
|
||||||
updates.append(
|
updates.append(
|
||||||
Lock(
|
Lock(
|
||||||
channel=channel.id,
|
channel=channel.id,
|
||||||
|
@ -79,7 +82,7 @@ class LockdownCog(CacheCog):
|
||||||
async def _lockdown_end(
|
async def _lockdown_end(
|
||||||
self,
|
self,
|
||||||
ctx: SlashContext,
|
ctx: SlashContext,
|
||||||
):
|
) -> None:
|
||||||
channels = ctx.guild.channels
|
channels = ctx.guild.channels
|
||||||
roles = ctx.guild.roles
|
roles = ctx.guild.roles
|
||||||
update = False
|
update = False
|
||||||
|
@ -90,13 +93,9 @@ class LockdownCog(CacheCog):
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
for role in roles:
|
for role in roles:
|
||||||
try:
|
with suppress(Exception):
|
||||||
await self._unlock_channel(channel, role, ctx.author)
|
await self._unlock_channel(channel, role, ctx.author)
|
||||||
except Exception:
|
|
||||||
continue # Just continue on error
|
|
||||||
update = True
|
update = True
|
||||||
if update:
|
if update:
|
||||||
Lock.objects(guild=ctx.guild.id, active=True).update(
|
Lock.objects(guild=ctx.guild.id, active=True).update(set__active=False)
|
||||||
set__active=False
|
|
||||||
)
|
|
||||||
await ctx.send("Server unlocked")
|
await ctx.send("Server unlocked")
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
|
"""J.A.R.V.I.S. MuteCog."""
|
||||||
from discord import Member
|
from discord import Member
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.utils import get
|
from discord.utils import get
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Mute, Setting
|
from jarvis.db.models import Mute
|
||||||
|
from jarvis.db.models import Setting
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
from jarvis.utils.permissions import admin_or_permissions
|
from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class MuteCog(commands.Cog):
|
class MuteCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. MuteCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -39,9 +44,7 @@ class MuteCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(mute_members=True)
|
@admin_or_permissions(mute_members=True)
|
||||||
async def _mute(
|
async def _mute(self, ctx: SlashContext, user: Member, reason: str, duration: int = 30) -> None:
|
||||||
self, ctx: SlashContext, user: Member, reason: str, duration: int = 30
|
|
||||||
):
|
|
||||||
if user == ctx.author:
|
if user == ctx.author:
|
||||||
await ctx.send("You cannot mute yourself.", hidden=True)
|
await ctx.send("You cannot mute yourself.", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -51,13 +54,10 @@ class MuteCog(commands.Cog):
|
||||||
if len(reason) > 100:
|
if len(reason) > 100:
|
||||||
await ctx.send("Reason must be < 100 characters", hidden=True)
|
await ctx.send("Reason must be < 100 characters", hidden=True)
|
||||||
return
|
return
|
||||||
mute_setting = Setting.objects(
|
mute_setting = Setting.objects(guild=ctx.guild.id, setting="mute").first()
|
||||||
guild=ctx.guild.id, setting="mute"
|
|
||||||
).first()
|
|
||||||
if not mute_setting:
|
if not mute_setting:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please configure a mute role "
|
"Please configure a mute role with /settings mute <role> first",
|
||||||
+ "with /settings mute <role> first",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -103,14 +103,11 @@ class MuteCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(mute_members=True)
|
@admin_or_permissions(mute_members=True)
|
||||||
async def _unmute(self, ctx: SlashContext, user: Member):
|
async def _unmute(self, ctx: SlashContext, user: Member) -> None:
|
||||||
mute_setting = Setting.objects(
|
mute_setting = Setting.objects(guild=ctx.guild.id, setting="mute").first()
|
||||||
guild=ctx.guild.id, setting="mute"
|
|
||||||
).first()
|
|
||||||
if not mute_setting:
|
if not mute_setting:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please configure a mute role with "
|
"Please configure a mute role with /settings mute <role> first.",
|
||||||
+ "/settings mute <role> first.",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -122,9 +119,7 @@ class MuteCog(commands.Cog):
|
||||||
await ctx.send("User is not muted.", hidden=True)
|
await ctx.send("User is not muted.", hidden=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
_ = Mute.objects(guild=ctx.guild.id, user=user.id).update(
|
_ = Mute.objects(guild=ctx.guild.id, user=user.id).update(set__active=False)
|
||||||
set__active=False
|
|
||||||
)
|
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="User Unmuted",
|
title="User Unmuted",
|
||||||
description=f"{user.mention} has been unmuted",
|
description=f"{user.mention} has been unmuted",
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
|
"""J.A.R.V.I.S. PurgeCog."""
|
||||||
from discord import TextChannel
|
from discord import TextChannel
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Autopurge, Purge
|
from jarvis.db.models import Autopurge
|
||||||
|
from jarvis.db.models import Purge
|
||||||
from jarvis.utils.permissions import admin_or_permissions
|
from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class PurgeCog(commands.Cog):
|
class PurgeCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. PurgeCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -24,7 +29,7 @@ class PurgeCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_messages=True)
|
@admin_or_permissions(manage_messages=True)
|
||||||
async def _purge(self, ctx: SlashContext, amount: int = 10):
|
async def _purge(self, ctx: SlashContext, amount: int = 10) -> None:
|
||||||
if amount < 1:
|
if amount < 1:
|
||||||
await ctx.send("Amount must be >= 1", hidden=True)
|
await ctx.send("Amount must be >= 1", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -61,9 +66,7 @@ class PurgeCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_messages=True)
|
@admin_or_permissions(manage_messages=True)
|
||||||
async def _autopurge_add(
|
async def _autopurge_add(self, ctx: SlashContext, channel: TextChannel, delay: int = 30) -> None:
|
||||||
self, ctx: SlashContext, channel: TextChannel, delay: int = 30
|
|
||||||
):
|
|
||||||
if not isinstance(channel, TextChannel):
|
if not isinstance(channel, TextChannel):
|
||||||
await ctx.send("Channel must be a TextChannel", hidden=True)
|
await ctx.send("Channel must be a TextChannel", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -73,9 +76,7 @@ class PurgeCog(commands.Cog):
|
||||||
elif delay > 300:
|
elif delay > 300:
|
||||||
await ctx.send("Delay must be < 5 minutes", hidden=True)
|
await ctx.send("Delay must be < 5 minutes", hidden=True)
|
||||||
return
|
return
|
||||||
autopurge = Autopurge.objects(
|
autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id).first()
|
||||||
guild=ctx.guild.id, channel=channel.id
|
|
||||||
).first()
|
|
||||||
if autopurge:
|
if autopurge:
|
||||||
await ctx.send("Autopurge already exists.", hidden=True)
|
await ctx.send("Autopurge already exists.", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -85,10 +86,7 @@ class PurgeCog(commands.Cog):
|
||||||
admin=ctx.author.id,
|
admin=ctx.author.id,
|
||||||
delay=delay,
|
delay=delay,
|
||||||
).save()
|
).save()
|
||||||
await ctx.send(
|
await ctx.send(f"Autopurge set up on {channel.mention}, delay is {delay} seconds")
|
||||||
f"Autopurge set up on {channel.mention}, "
|
|
||||||
+ f"delay is {delay} seconds"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="autopurge",
|
base="autopurge",
|
||||||
|
@ -104,7 +102,7 @@ class PurgeCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_messages=True)
|
@admin_or_permissions(manage_messages=True)
|
||||||
async def _autopurge_remove(self, ctx: SlashContext, channel: TextChannel):
|
async def _autopurge_remove(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id)
|
autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id)
|
||||||
if not autopurge:
|
if not autopurge:
|
||||||
await ctx.send("Autopurge does not exist.", hidden=True)
|
await ctx.send("Autopurge does not exist.", hidden=True)
|
||||||
|
@ -132,15 +130,11 @@ class PurgeCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_messages=True)
|
@admin_or_permissions(manage_messages=True)
|
||||||
async def _autopurge_update(
|
async def _autopurge_update(self, ctx: SlashContext, channel: TextChannel, delay: int) -> None:
|
||||||
self, ctx: SlashContext, channel: TextChannel, delay: int
|
|
||||||
):
|
|
||||||
autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id)
|
autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id)
|
||||||
if not autopurge:
|
if not autopurge:
|
||||||
await ctx.send("Autopurge does not exist.", hidden=True)
|
await ctx.send("Autopurge does not exist.", hidden=True)
|
||||||
return
|
return
|
||||||
autopurge.delay = delay
|
autopurge.delay = delay
|
||||||
autopurge.save()
|
autopurge.save()
|
||||||
await ctx.send(
|
await ctx.send(f"Autopurge delay updated to {delay} seconds on {channel.mention}.")
|
||||||
f"Autopurge delay updated to {delay} seconds on {channel.mention}."
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. RolepingCog."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from ButtonPaginator import Paginator
|
from ButtonPaginator import Paginator
|
||||||
from discord import Member, Role
|
from discord import Member
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord import Role
|
||||||
|
from discord.ext.commands import Bot
|
||||||
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.model import ButtonStyle
|
from discord_slash.model import ButtonStyle
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
|
@ -14,7 +19,9 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class RolepingCog(CacheCog):
|
class RolepingCog(CacheCog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. RolepingCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -31,12 +38,10 @@ class RolepingCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _roleping_add(self, ctx: SlashContext, role: Role):
|
async def _roleping_add(self, ctx: SlashContext, role: Role) -> None:
|
||||||
roleping = Roleping.objects(guild=ctx.guild.id, role=role.id).first()
|
roleping = Roleping.objects(guild=ctx.guild.id, role=role.id).first()
|
||||||
if roleping:
|
if roleping:
|
||||||
await ctx.send(
|
await ctx.send(f"Role `{role.name}` already in roleping.", hidden=True)
|
||||||
f"Role `{role.name}` already in roleping.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
_ = Roleping(
|
_ = Roleping(
|
||||||
role=role.id,
|
role=role.id,
|
||||||
|
@ -61,7 +66,7 @@ class RolepingCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _roleping_remove(self, ctx: SlashContext, role: Role):
|
async def _roleping_remove(self, ctx: SlashContext, role: Role) -> None:
|
||||||
roleping = Roleping.objects(guild=ctx.guild.id, role=role.id)
|
roleping = Roleping.objects(guild=ctx.guild.id, role=role.id)
|
||||||
if not roleping:
|
if not roleping:
|
||||||
await ctx.send("Roleping does not exist", hidden=True)
|
await ctx.send("Roleping does not exist", hidden=True)
|
||||||
|
@ -75,13 +80,12 @@ class RolepingCog(CacheCog):
|
||||||
name="list",
|
name="list",
|
||||||
description="List all blocklisted roles",
|
description="List all blocklisted roles",
|
||||||
)
|
)
|
||||||
async def _roleping_list(self, ctx: SlashContext):
|
async def _roleping_list(self, ctx: SlashContext) -> None:
|
||||||
exists = self.check_cache(ctx)
|
exists = self.check_cache(ctx)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -94,18 +98,9 @@ class RolepingCog(CacheCog):
|
||||||
embeds = []
|
embeds = []
|
||||||
for roleping in rolepings:
|
for roleping in rolepings:
|
||||||
role = ctx.guild.get_role(roleping.role)
|
role = ctx.guild.get_role(roleping.role)
|
||||||
bypass_roles = list(
|
bypass_roles = list(filter(lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles))
|
||||||
filter(
|
bypass_roles = [r.mention or "||`[redacted]`||" for r in bypass_roles]
|
||||||
lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles
|
bypass_users = [ctx.guild.get_member(u).mention or "||`[redacted]`||" for u in roleping.bypass["users"]]
|
||||||
)
|
|
||||||
)
|
|
||||||
bypass_roles = [
|
|
||||||
r.mention or "||`[redacted]`||" for r in bypass_roles
|
|
||||||
]
|
|
||||||
bypass_users = [
|
|
||||||
ctx.guild.get_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"]
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
|
@ -115,9 +110,7 @@ class RolepingCog(CacheCog):
|
||||||
fields=[
|
fields=[
|
||||||
Field(
|
Field(
|
||||||
name="Created At",
|
name="Created At",
|
||||||
value=roleping.created_at.strftime(
|
value=roleping.created_at.strftime("%a, %b %d, %Y %I:%M %p"),
|
||||||
"%a, %b %d, %Y %I:%M %p"
|
|
||||||
),
|
|
||||||
inline=False,
|
inline=False,
|
||||||
),
|
),
|
||||||
Field(name="Active", value=str(roleping.active)),
|
Field(name="Active", value=str(roleping.active)),
|
||||||
|
@ -136,12 +129,8 @@ class RolepingCog(CacheCog):
|
||||||
if not admin:
|
if not admin:
|
||||||
admin = self.bot.user
|
admin = self.bot.user
|
||||||
|
|
||||||
embed.set_author(
|
embed.set_author(name=admin.nick or admin.name, icon_url=admin.avatar_url)
|
||||||
name=admin.nick or admin.name, icon_url=admin.avatar_url
|
embed.set_footer(text=f"{admin.name}#{admin.discriminator} | {admin.id}")
|
||||||
)
|
|
||||||
embed.set_footer(
|
|
||||||
text=f"{admin.name}#{admin.discriminator} | {admin.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
embeds.append(embed)
|
embeds.append(embed)
|
||||||
|
|
||||||
|
@ -191,14 +180,10 @@ class RolepingCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _roleping_bypass_user(
|
async def _roleping_bypass_user(self, ctx: SlashContext, user: Member, rping: Role) -> None:
|
||||||
self, ctx: SlashContext, user: Member, rping: Role
|
|
||||||
):
|
|
||||||
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
||||||
if not roleping:
|
if not roleping:
|
||||||
await ctx.send(
|
await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True)
|
||||||
f"Roleping not configured for {rping.mention}", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if user.id in roleping.bypass["users"]:
|
if user.id in roleping.bypass["users"]:
|
||||||
|
@ -207,29 +192,23 @@ class RolepingCog(CacheCog):
|
||||||
|
|
||||||
if len(roleping.bypass["users"]) == 10:
|
if len(roleping.bypass["users"]) == 10:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Already have 10 users in bypass. "
|
"Already have 10 users in bypass. Please consider using roles for roleping bypass",
|
||||||
"Please consider using roles for roleping bypass",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
matching_role = list(
|
matching_role = list(filter(lambda x: x.id in roleping.bypass["roles"], user.roles))
|
||||||
filter(lambda x: x.id in roleping.bypass["roles"], user.roles)
|
|
||||||
)
|
|
||||||
|
|
||||||
if matching_role:
|
if matching_role:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"{user.mention} already has bypass "
|
f"{user.mention} already has bypass via {matching_role[0].mention}",
|
||||||
f"via {matching_role[0].mention}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
roleping.bypass["users"].append(user.id)
|
roleping.bypass["users"].append(user.id)
|
||||||
roleping.save()
|
roleping.save()
|
||||||
await ctx.send(
|
await ctx.send(f"{user.nick or user.name} user bypass added for `{rping.name}`")
|
||||||
f"{user.nick or user.name} user bypass added for `{rping.name}`"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="roleping",
|
base="roleping",
|
||||||
|
@ -254,14 +233,10 @@ class RolepingCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _roleping_bypass_role(
|
async def _roleping_bypass_role(self, ctx: SlashContext, role: Role, rping: Role) -> None:
|
||||||
self, ctx: SlashContext, role: Role, rping: Role
|
|
||||||
):
|
|
||||||
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
||||||
if not roleping:
|
if not roleping:
|
||||||
await ctx.send(
|
await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True)
|
||||||
f"Roleping not configured for {rping.mention}", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if role.id in roleping.bypass["roles"]:
|
if role.id in roleping.bypass["roles"]:
|
||||||
|
@ -270,8 +245,7 @@ class RolepingCog(CacheCog):
|
||||||
|
|
||||||
if len(roleping.bypass["roles"]) == 10:
|
if len(roleping.bypass["roles"]) == 10:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Already have 10 roles in bypass. "
|
"Already have 10 roles in bypass. Please consider consolidating roles for roleping bypass",
|
||||||
"Please consider consolidating roles for roleping bypass",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -303,14 +277,10 @@ class RolepingCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _roleping_restore_user(
|
async def _roleping_restore_user(self, ctx: SlashContext, user: Member, rping: Role) -> None:
|
||||||
self, ctx: SlashContext, user: Member, rping: Role
|
|
||||||
):
|
|
||||||
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
||||||
if not roleping:
|
if not roleping:
|
||||||
await ctx.send(
|
await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True)
|
||||||
f"Roleping not configured for {rping.mention}", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if user.id not in roleping.bypass["users"]:
|
if user.id not in roleping.bypass["users"]:
|
||||||
|
@ -319,9 +289,7 @@ class RolepingCog(CacheCog):
|
||||||
|
|
||||||
roleping.bypass["users"].delete(user.id)
|
roleping.bypass["users"].delete(user.id)
|
||||||
roleping.save()
|
roleping.save()
|
||||||
await ctx.send(
|
await ctx.send(f"{user.nick or user.name} user bypass removed for `{rping.name}`")
|
||||||
f"{user.nick or user.name} user bypass removed for `{rping.name}`"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="roleping",
|
base="roleping",
|
||||||
|
@ -346,14 +314,10 @@ class RolepingCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _roleping_restore_role(
|
async def _roleping_restore_role(self, ctx: SlashContext, role: Role, rping: Role) -> None:
|
||||||
self, ctx: SlashContext, role: Role, rping: Role
|
|
||||||
):
|
|
||||||
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first()
|
||||||
if not roleping:
|
if not roleping:
|
||||||
await ctx.send(
|
await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True)
|
||||||
f"Roleping not configured for {rping.mention}", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if role.id in roleping.bypass["roles"]:
|
if role.id in roleping.bypass["roles"]:
|
||||||
|
@ -362,8 +326,7 @@ class RolepingCog(CacheCog):
|
||||||
|
|
||||||
if len(roleping.bypass["roles"]) == 10:
|
if len(roleping.bypass["roles"]) == 10:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Already have 10 roles in bypass. "
|
"Already have 10 roles in bypass. Please consider consolidating roles for roleping bypass",
|
||||||
"Please consider consolidating roles for roleping bypass",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. WarningCog."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from ButtonPaginator import Paginator
|
from ButtonPaginator import Paginator
|
||||||
from discord import User
|
from discord import User
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord.ext.commands import Bot
|
||||||
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.model import ButtonStyle
|
from discord_slash.model import ButtonStyle
|
||||||
from discord_slash.utils.manage_commands import create_choice, create_option
|
from discord_slash.utils.manage_commands import create_choice
|
||||||
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Warning
|
from jarvis.db.models import Warning
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
|
@ -14,7 +19,9 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class WarningCog(CacheCog):
|
class WarningCog(CacheCog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. WarningCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -42,9 +49,7 @@ class WarningCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _warn(
|
async def _warn(self, ctx: SlashContext, user: User, reason: str, duration: int = 24) -> None:
|
||||||
self, ctx: SlashContext, user: User, reason: str, duration: int = 24
|
|
||||||
):
|
|
||||||
if len(reason) > 100:
|
if len(reason) > 100:
|
||||||
await ctx.send("Reason must be < 100 characters", hidden=True)
|
await ctx.send("Reason must be < 100 characters", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -100,14 +105,13 @@ class WarningCog(CacheCog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _warnings(self, ctx: SlashContext, user: User, active: bool = 1):
|
async def _warnings(self, ctx: SlashContext, user: User, active: bool = 1) -> None:
|
||||||
active = bool(active)
|
active = bool(active)
|
||||||
exists = self.check_cache(ctx, user_id=user.id, active=active)
|
exists = self.check_cache(ctx, user_id=user.id, active=active)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -115,9 +119,7 @@ class WarningCog(CacheCog):
|
||||||
user=user.id,
|
user=user.id,
|
||||||
guild=ctx.guild.id,
|
guild=ctx.guild.id,
|
||||||
).order_by("-created_at")
|
).order_by("-created_at")
|
||||||
active_warns = Warning.objects(
|
active_warns = Warning.objects(user=user.id, guild=ctx.guild.id, active=True).order_by("-created_at")
|
||||||
user=user.id, guild=ctx.guild.id, active=True
|
|
||||||
).order_by("-created_at")
|
|
||||||
|
|
||||||
pages = []
|
pages = []
|
||||||
if active:
|
if active:
|
||||||
|
@ -139,30 +141,23 @@ class WarningCog(CacheCog):
|
||||||
admin_name = f"{admin.name}#{admin.discriminator}"
|
admin_name = f"{admin.name}#{admin.discriminator}"
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name=warn.created_at.strftime(
|
name=warn.created_at.strftime("%Y-%m-%d %H:%M:%S UTC"),
|
||||||
"%Y-%m-%d %H:%M:%S UTC"
|
value=f"{warn.reason}\nAdmin: {admin_name}\n\u200b",
|
||||||
),
|
|
||||||
value=f"{warn.reason}\n"
|
|
||||||
+ f"Admin: {admin_name}\n"
|
|
||||||
+ "\u200b",
|
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for i in range(0, len(fields), 5):
|
for i in range(0, len(fields), 5):
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="Warnings",
|
title="Warnings",
|
||||||
description=f"{warnings.count()} total | "
|
description=f"{warnings.count()} total | {active_warns.count()} currently active",
|
||||||
+ f"{active_warns.count()} currently active",
|
fields=fields[i : i + 5], # noqa: E203
|
||||||
fields=fields[i : i + 5],
|
|
||||||
)
|
)
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name=user.name + "#" + user.discriminator,
|
name=user.name + "#" + user.discriminator,
|
||||||
icon_url=user.avatar_url,
|
icon_url=user.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(url=ctx.guild.icon_url)
|
embed.set_thumbnail(url=ctx.guild.icon_url)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{user.name}#{user.discriminator} | {user.id}")
|
||||||
text=f"{user.name}#{user.discriminator} | {user.id}"
|
|
||||||
)
|
|
||||||
pages.append(embed)
|
pages.append(embed)
|
||||||
else:
|
else:
|
||||||
fields = []
|
fields = []
|
||||||
|
@ -179,9 +174,8 @@ class WarningCog(CacheCog):
|
||||||
for i in range(0, len(fields), 5):
|
for i in range(0, len(fields), 5):
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="Warnings",
|
title="Warnings",
|
||||||
description=f"{warnings.count()} total | "
|
description=f"{warnings.count()} total | {active_warns.count()} currently active",
|
||||||
+ f"{active_warns.count()} currently active",
|
fields=fields[i : i + 5], # noqa: E203
|
||||||
fields=fields[i : i + 5],
|
|
||||||
)
|
)
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name=user.name + "#" + user.discriminator,
|
name=user.name + "#" + user.discriminator,
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
"""J.A.R.V.I.S. Autoreact Cog."""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from discord import TextChannel
|
from discord import TextChannel
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.data.unicode import emoji_list
|
from jarvis.data.unicode import emoji_list
|
||||||
|
@ -12,7 +14,9 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class AutoReactCog(commands.Cog):
|
class AutoReactCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Autoreact Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.custom_emote = re.compile(r"^<:\w+:(\d+)>$")
|
self.custom_emote = re.compile(r"^<:\w+:(\d+)>$")
|
||||||
|
|
||||||
|
@ -30,17 +34,13 @@ class AutoReactCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _autoreact_create(self, ctx: SlashContext, channel: TextChannel):
|
async def _autoreact_create(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
if not isinstance(channel, TextChannel):
|
if not isinstance(channel, TextChannel):
|
||||||
await ctx.send("Channel must be a text channel", hidden=True)
|
await ctx.send("Channel must be a text channel", hidden=True)
|
||||||
return
|
return
|
||||||
exists = Autoreact.objects(
|
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first()
|
||||||
guild=ctx.guild.id, channel=channel.id
|
|
||||||
).first()
|
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.send(
|
await ctx.send(f"Autoreact already exists for {channel.mention}.", hidden=True)
|
||||||
f"Autoreact already exists for {channel.mention}.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
_ = Autoreact(
|
_ = Autoreact(
|
||||||
|
@ -65,16 +65,12 @@ class AutoReactCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _autoreact_delete(self, ctx, channel: TextChannel):
|
async def _autoreact_delete(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
exists = Autoreact.objects(
|
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).delete()
|
||||||
guild=ctx.guild.id, channel=channel.id
|
|
||||||
).delete()
|
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.send(f"Autoreact removed from {channel.mention}")
|
await ctx.send(f"Autoreact removed from {channel.mention}")
|
||||||
else:
|
else:
|
||||||
await ctx.send(
|
await ctx.send(f"Autoreact not found on {channel.mention}", hidden=True)
|
||||||
f"Autoreact not found on {channel.mention}", hidden=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="autoreact",
|
base="autoreact",
|
||||||
|
@ -96,32 +92,24 @@ class AutoReactCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _autoreact_add(self, ctx, channel: TextChannel, emote: str):
|
async def _autoreact_add(self, ctx: SlashContext, channel: TextChannel, emote: str) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
custom_emoji = self.custom_emote.match(emote)
|
custom_emoji = self.custom_emote.match(emote)
|
||||||
standard_emoji = emote in emoji_list
|
standard_emoji = emote in emoji_list
|
||||||
if not custom_emoji and not standard_emoji:
|
if not custom_emoji and not standard_emoji:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use either an emote from this server"
|
"Please use either an emote from this server or a unicode emoji.",
|
||||||
+ " or a unicode emoji.",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if custom_emoji:
|
if custom_emoji:
|
||||||
emoji_id = int(custom_emoji.group(1))
|
emoji_id = int(custom_emoji.group(1))
|
||||||
if not find(lambda x: x.id == emoji_id, ctx.guild.emojis):
|
if not find(lambda x: x.id == emoji_id, ctx.guild.emojis):
|
||||||
await ctx.send(
|
await ctx.send("Please use a custom emote from this server.", hidden=True)
|
||||||
"Please use a custom emote from this server.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
exists = Autoreact.objects(
|
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first()
|
||||||
guild=ctx.guild.id, channel=channel.id
|
|
||||||
).first()
|
|
||||||
if not exists:
|
if not exists:
|
||||||
await ctx.send(
|
await ctx.send(f"Please create autoreact first with /autoreact create {channel.mention}")
|
||||||
"Please create autoreact first with "
|
|
||||||
+ f"/autoreact create {channel.mention}"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
if emote in exists.reactions:
|
if emote in exists.reactions:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
|
@ -131,8 +119,7 @@ class AutoReactCog(commands.Cog):
|
||||||
return
|
return
|
||||||
if len(exists.reactions) >= 5:
|
if len(exists.reactions) >= 5:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Max number of reactions hit. "
|
"Max number of reactions hit. Remove a different one to add this one",
|
||||||
+ "Remove a different one to add this one",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -160,14 +147,11 @@ class AutoReactCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _autoreact_remove(self, ctx, channel: TextChannel, emote: str):
|
async def _autoreact_remove(self, ctx: SlashContext, channel: TextChannel, emote: str) -> None:
|
||||||
exists = Autoreact.objects(
|
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first()
|
||||||
guild=ctx.guild.id, channel=channel.id
|
|
||||||
).first()
|
|
||||||
if not exists:
|
if not exists:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please create autoreact first with "
|
f"Please create autoreact first with /autoreact create {channel.mention}",
|
||||||
+ f"/autoreact create {channel.mention}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -195,27 +179,22 @@ class AutoReactCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _autoreact_list(self, ctx, channel: TextChannel):
|
async def _autoreact_list(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
exists = Autoreact.objects(
|
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first()
|
||||||
guild=ctx.guild.id, channel=channel.id
|
|
||||||
).first()
|
|
||||||
if not exists:
|
if not exists:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please create autoreact first with "
|
f"Please create autoreact first with /autoreact create {channel.mention}",
|
||||||
+ f"/autoreact create {channel.mention}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
message = ""
|
message = ""
|
||||||
if len(exists.reactions) > 0:
|
if len(exists.reactions) > 0:
|
||||||
message = (
|
message = f"Current active autoreacts on {channel.mention}:\n" + "\n".join(exists.reactions)
|
||||||
f"Current active autoreacts on {channel.mention}:\n"
|
|
||||||
+ "\n".join(exists.reactions)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
message = f"No reactions set on {channel.mention}"
|
message = f"No reactions set on {channel.mention}"
|
||||||
await ctx.send(message)
|
await ctx.send(message)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add AutoReactCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(AutoReactCog(bot))
|
bot.add_cog(AutoReactCog(bot))
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
|
"""J.A.R.V.I.S. Complete the Code 2 Cog."""
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import pymongo
|
|
||||||
from ButtonPaginator import Paginator
|
from ButtonPaginator import Paginator
|
||||||
from discord import Member, User
|
from discord import Member
|
||||||
|
from discord import User
|
||||||
|
from discord.commands.ext import Bot
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.ext.tasks import loop
|
from discord_slash import cog_ext
|
||||||
from discord.utils import find
|
from discord_slash import SlashContext
|
||||||
from discord_slash import SlashContext, cog_ext
|
|
||||||
from discord_slash.model import ButtonStyle
|
from discord_slash.model import ButtonStyle
|
||||||
|
|
||||||
from jarvis.db.models import Guess
|
from jarvis.db.models import Guess
|
||||||
|
@ -26,11 +28,16 @@ invites = re.compile(
|
||||||
|
|
||||||
|
|
||||||
class CTCCog(CacheCog):
|
class CTCCog(CacheCog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Complete the Code 2 Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
self._session = aiohttp.ClientSession()
|
self._session = aiohttp.ClientSession()
|
||||||
self.url = "https://completethecodetwo.cards/pw"
|
self.url = "https://completethecodetwo.cards/pw"
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._session.close()
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="ctc2",
|
base="ctc2",
|
||||||
name="about",
|
name="about",
|
||||||
|
@ -38,7 +45,7 @@ class CTCCog(CacheCog):
|
||||||
guild_ids=guild_ids,
|
guild_ids=guild_ids,
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _about(self, ctx):
|
async def _about(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send("See https://completethecode.com for more information")
|
await ctx.send("See https://completethecode.com for more information")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -48,25 +55,22 @@ class CTCCog(CacheCog):
|
||||||
guild_ids=guild_ids,
|
guild_ids=guild_ids,
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _pw(self, ctx: SlashContext, guess: str):
|
async def _pw(self, ctx: SlashContext, guess: str) -> None:
|
||||||
if len(guess) > 800:
|
if len(guess) > 800:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Listen here, dipshit. Don't be like "
|
"Listen here, dipshit. Don't be like <@256110768724901889>. Make your guesses < 800 characters.",
|
||||||
+ "<@256110768724901889>. Make your guesses < 800 characters.",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
elif not valid.fullmatch(guess):
|
elif not valid.fullmatch(guess):
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Listen here, dipshit. Don't be like "
|
"Listen here, dipshit. Don't be like <@256110768724901889>. Make your guesses *readable*.",
|
||||||
+ "<@256110768724901889>. Make your guesses *readable*.",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
elif invites.search(guess):
|
elif invites.search(guess):
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Listen here, dipshit. "
|
"Listen here, dipshit. No using this to bypass sending invite links.",
|
||||||
+ "No using this to bypass sending invite links.",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -77,9 +81,7 @@ class CTCCog(CacheCog):
|
||||||
result = await self._session.post(self.url, data=guess)
|
result = await self._session.post(self.url, data=guess)
|
||||||
correct = False
|
correct = False
|
||||||
if 200 <= result.status < 400:
|
if 200 <= result.status < 400:
|
||||||
await ctx.send(
|
await ctx.send(f"{ctx.author.mention} got it! Password is {guess}!")
|
||||||
f"{ctx.author.mention} got it! Password is {guess}!"
|
|
||||||
)
|
|
||||||
correct = True
|
correct = True
|
||||||
else:
|
else:
|
||||||
await ctx.send("Nope.", hidden=True)
|
await ctx.send("Nope.", hidden=True)
|
||||||
|
@ -92,13 +94,12 @@ class CTCCog(CacheCog):
|
||||||
guild_ids=guild_ids,
|
guild_ids=guild_ids,
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _guesses(self, ctx: SlashContext):
|
async def _guesses(self, ctx: SlashContext) -> None:
|
||||||
exists = self.check_cache(ctx)
|
exists = self.check_cache(ctx)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -127,7 +128,7 @@ class CTCCog(CacheCog):
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="completethecodetwo.cards guesses",
|
title="completethecodetwo.cards guesses",
|
||||||
description=f"{len(fields)} guesses so far",
|
description=f"{len(fields)} guesses so far",
|
||||||
fields=fields[i : i + 5],
|
fields=fields[i : i + 5], # noqa: E203
|
||||||
url="https://completethecodetwo.cards",
|
url="https://completethecodetwo.cards",
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(url="https://dev.zevaryx.com/db_logo.png")
|
embed.set_thumbnail(url="https://dev.zevaryx.com/db_logo.png")
|
||||||
|
@ -161,5 +162,6 @@ class CTCCog(CacheCog):
|
||||||
await paginator.start()
|
await paginator.start()
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: Bot) -> None:
|
||||||
|
"""Add CTCCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(CTCCog(bot))
|
bot.add_cog(CTCCog(bot))
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
"""J.A.R.V.I.S. dbrand cog."""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
|
@ -20,7 +22,7 @@ class DbrandCog(commands.Cog):
|
||||||
Mostly support functions. Credit @cpixl for the shipping API
|
Mostly support functions. Credit @cpixl for the shipping API
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.base_url = "https://dbrand.com/"
|
self.base_url = "https://dbrand.com/"
|
||||||
self._session = aiohttp.ClientSession()
|
self._session = aiohttp.ClientSession()
|
||||||
|
@ -28,6 +30,9 @@ class DbrandCog(commands.Cog):
|
||||||
self.api_url = get_config().urls["dbrand_shipping"]
|
self.api_url = get_config().urls["dbrand_shipping"]
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._session.close()
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="db",
|
base="db",
|
||||||
name="skin",
|
name="skin",
|
||||||
|
@ -35,7 +40,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="See what skins are available",
|
description="See what skins are available",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _skin(self, ctx):
|
async def _skin(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(self.base_url + "shop/skins")
|
await ctx.send(self.base_url + "shop/skins")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -45,7 +50,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="Get some robot camo. Make Tony Stark proud",
|
description="Get some robot camo. Make Tony Stark proud",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _camo(self, ctx):
|
async def _camo(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(self.base_url + "shop/special-edition/robot-camo")
|
await ctx.send(self.base_url + "shop/special-edition/robot-camo")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -55,7 +60,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="See devices with Grip support",
|
description="See devices with Grip support",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _grip(self, ctx):
|
async def _grip(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(self.base_url + "shop/grip/#grip-devices")
|
await ctx.send(self.base_url + "shop/grip/#grip-devices")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -65,10 +70,8 @@ class DbrandCog(commands.Cog):
|
||||||
description="Contact support",
|
description="Contact support",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _contact(self, ctx):
|
async def _contact(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(
|
await ctx.send("Contact dbrand support here: " + self.base_url + "contact")
|
||||||
"Contact dbrand support here: " + self.base_url + "contact"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="db",
|
base="db",
|
||||||
|
@ -77,10 +80,8 @@ class DbrandCog(commands.Cog):
|
||||||
description="Contact support",
|
description="Contact support",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _support(self, ctx):
|
async def _support(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(
|
await ctx.send("Contact dbrand support here: " + self.base_url + "contact")
|
||||||
"Contact dbrand support here: " + self.base_url + "contact"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="db",
|
base="db",
|
||||||
|
@ -89,7 +90,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="Get your order status",
|
description="Get your order status",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _orderstat(self, ctx):
|
async def _orderstat(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(self.base_url + "order-status")
|
await ctx.send(self.base_url + "order-status")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -99,7 +100,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="Get your order status",
|
description="Get your order status",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _orders(self, ctx):
|
async def _orders(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(self.base_url + "order-status")
|
await ctx.send(self.base_url + "order-status")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -109,7 +110,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="dbrand status",
|
description="dbrand status",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _status(self, ctx):
|
async def _status(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(self.base_url + "status")
|
await ctx.send(self.base_url + "status")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -119,7 +120,7 @@ class DbrandCog(commands.Cog):
|
||||||
description="Give us your money!",
|
description="Give us your money!",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _buy(self, ctx):
|
async def _buy(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send("Give us your money! " + self.base_url + "shop")
|
await ctx.send("Give us your money! " + self.base_url + "shop")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -129,10 +130,8 @@ class DbrandCog(commands.Cog):
|
||||||
description="(not) extortion",
|
description="(not) extortion",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _extort(self, ctx):
|
async def _extort(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(
|
await ctx.send("Be (not) extorted here: " + self.base_url + "not-extortion")
|
||||||
"Be (not) extorted here: " + self.base_url + "not-extortion"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="db",
|
base="db",
|
||||||
|
@ -141,10 +140,8 @@ class DbrandCog(commands.Cog):
|
||||||
guild_ids=guild_ids,
|
guild_ids=guild_ids,
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _wallpapers(self, ctx):
|
async def _wallpapers(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(
|
await ctx.send("Get robot camo wallpapers here: https://db.io/wallpapers")
|
||||||
"Get robot camo wallpapers here: https://db.io/wallpapers"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="db",
|
base="db",
|
||||||
|
@ -155,8 +152,7 @@ class DbrandCog(commands.Cog):
|
||||||
(
|
(
|
||||||
create_option(
|
create_option(
|
||||||
name="search",
|
name="search",
|
||||||
description="Country search query (2 character code, "
|
description="Country search query (2 character code, country name, emoji)",
|
||||||
+ "country name, emoji)",
|
|
||||||
option_type=3,
|
option_type=3,
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
|
@ -164,7 +160,7 @@ class DbrandCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _shipping(self, ctx, *, search: str):
|
async def _shipping(self, ctx: SlashContext, search: str) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
if not re.match(r"^[A-Z- ]+$", search, re.IGNORECASE):
|
if not re.match(r"^[A-Z- ]+$", search, re.IGNORECASE):
|
||||||
if re.match(
|
if re.match(
|
||||||
|
@ -174,9 +170,7 @@ class DbrandCog(commands.Cog):
|
||||||
):
|
):
|
||||||
# Magic number, subtract from flag char to get ascii char
|
# Magic number, subtract from flag char to get ascii char
|
||||||
uni2ascii = 127365
|
uni2ascii = 127365
|
||||||
search = chr(ord(search[0]) - uni2ascii) + chr(
|
search = chr(ord(search[0]) - uni2ascii) + chr(ord(search[1]) - uni2ascii)
|
||||||
ord(search[1]) - uni2ascii
|
|
||||||
)
|
|
||||||
elif search == "🏳️":
|
elif search == "🏳️":
|
||||||
search = "fr"
|
search = "fr"
|
||||||
else:
|
else:
|
||||||
|
@ -184,11 +178,7 @@ class DbrandCog(commands.Cog):
|
||||||
await ctx.send("Please use text to search for shipping.")
|
await ctx.send("Please use text to search for shipping.")
|
||||||
return
|
return
|
||||||
if len(search) > 2:
|
if len(search) > 2:
|
||||||
matches = [
|
matches = [x["code"] for x in shipping_lookup if search.lower() in x["country"]]
|
||||||
x["code"]
|
|
||||||
for x in shipping_lookup
|
|
||||||
if search.lower() in x["country"]
|
|
||||||
]
|
|
||||||
if len(matches) > 0:
|
if len(matches) > 0:
|
||||||
search = matches[0]
|
search = matches[0]
|
||||||
dest = search.lower()
|
dest = search.lower()
|
||||||
|
@ -202,17 +192,11 @@ class DbrandCog(commands.Cog):
|
||||||
data = None
|
data = None
|
||||||
self.cache[dest] = data
|
self.cache[dest] = data
|
||||||
fields = None
|
fields = None
|
||||||
if (
|
if data is not None and data["is_valid"] and data["shipping_available"]:
|
||||||
data is not None
|
|
||||||
and data["is_valid"]
|
|
||||||
and data["shipping_available"]
|
|
||||||
):
|
|
||||||
fields = []
|
fields = []
|
||||||
fields.append(Field(data["short-name"], data["time-title"]))
|
fields.append(Field(data["short-name"], data["time-title"]))
|
||||||
for service in data["shipping_services_available"][1:]:
|
for service in data["shipping_services_available"][1:]:
|
||||||
service_data = await self._session.get(
|
service_data = await self._session.get(self.api_url + dest + "/" + service["url"])
|
||||||
self.api_url + dest + "/" + service["url"]
|
|
||||||
)
|
|
||||||
if service_data.status > 400:
|
if service_data.status > 400:
|
||||||
continue
|
continue
|
||||||
service_data = await service_data.json()
|
service_data = await service_data.json()
|
||||||
|
@ -222,22 +206,13 @@ class DbrandCog(commands.Cog):
|
||||||
service_data["time-title"],
|
service_data["time-title"],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
country = "-".join(
|
country = "-".join(x for x in data["country"].split(" ") if x != "the")
|
||||||
x for x in data["country"].split(" ") if x != "the"
|
|
||||||
)
|
|
||||||
country_urlsafe = country.replace("-", "%20")
|
country_urlsafe = country.replace("-", "%20")
|
||||||
description = (
|
description = (
|
||||||
"Click the link above to "
|
f"Click the link above to see shipping time to {data['country']}."
|
||||||
+ "see shipping time to {data['country']}."
|
"\n[View all shipping destinations](https://dbrand.com/shipping)"
|
||||||
)
|
" | [Check shipping status]"
|
||||||
description += (
|
f"(https://dbrand.com/status#main-content:~:text={country_urlsafe})"
|
||||||
"\n[View all shipping destinations]"
|
|
||||||
+ "(https://dbrand.com/shipping)"
|
|
||||||
)
|
|
||||||
description += " | [Check shipping status]"
|
|
||||||
description += (
|
|
||||||
"(https://dbrand.com/status"
|
|
||||||
+ f"#main-content:~:text={country_urlsafe})"
|
|
||||||
)
|
)
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="Shipping to {}".format(data["country"]),
|
title="Shipping to {}".format(data["country"]),
|
||||||
|
@ -255,8 +230,9 @@ class DbrandCog(commands.Cog):
|
||||||
elif not data["is_valid"]:
|
elif not data["is_valid"]:
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="Check Shipping Times",
|
title="Check Shipping Times",
|
||||||
description="Country not found.\nYou can [view all shipping "
|
description=(
|
||||||
+ "destinations here](https://dbrand.com/shipping)",
|
"Country not found.\nYou can [view all shipping " "destinations here](https://dbrand.com/shipping)"
|
||||||
|
),
|
||||||
fields=[],
|
fields=[],
|
||||||
url="https://dbrand.com/shipping",
|
url="https://dbrand.com/shipping",
|
||||||
color="#FFBB00",
|
color="#FFBB00",
|
||||||
|
@ -270,9 +246,11 @@ class DbrandCog(commands.Cog):
|
||||||
elif not data["shipping_available"]:
|
elif not data["shipping_available"]:
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title="Shipping to {}".format(data["country"]),
|
title="Shipping to {}".format(data["country"]),
|
||||||
description="No shipping available.\nTime to move to a country"
|
description=(
|
||||||
+ " that has shipping available.\nYou can [find a new country "
|
"No shipping available.\nTime to move to a country"
|
||||||
+ "to live in here](https://dbrand.com/shipping)",
|
" that has shipping available.\nYou can [find a new country "
|
||||||
|
"to live in here](https://dbrand.com/shipping)"
|
||||||
|
),
|
||||||
fields=[],
|
fields=[],
|
||||||
url="https://dbrand.com/shipping",
|
url="https://dbrand.com/shipping",
|
||||||
color="#FFBB00",
|
color="#FFBB00",
|
||||||
|
@ -285,5 +263,6 @@ class DbrandCog(commands.Cog):
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add dbrandcog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(DbrandCog(bot))
|
bot.add_cog(DbrandCog(bot))
|
||||||
|
|
|
@ -1,42 +1,34 @@
|
||||||
|
"""J.A.R.V.I.S. Developer Cog."""
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess # noqa: S404
|
||||||
import uuid as uuidpy
|
import uuid as uuidpy
|
||||||
|
from typing import Any
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
import ulid as ulidpy
|
import ulid as ulidpy
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import cog_ext
|
from discord_slash import cog_ext
|
||||||
from discord_slash.utils.manage_commands import create_choice, create_option
|
from discord_slash import SlashContext
|
||||||
|
from discord_slash.utils.manage_commands import create_choice
|
||||||
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.utils import build_embed, convert_bytesize
|
from jarvis.utils import build_embed
|
||||||
|
from jarvis.utils import convert_bytesize
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
|
||||||
supported_hashes = {
|
supported_hashes = {x for x in hashlib.algorithms_guaranteed if "shake" not in x}
|
||||||
x for x in hashlib.algorithms_guaranteed if "shake" not in x
|
|
||||||
}
|
|
||||||
|
|
||||||
OID_VERIFY = re.compile(r"^([1-9][0-9]{0,3}|0)(\.([1-9][0-9]{0,3}|0)){5,13}$")
|
OID_VERIFY = re.compile(r"^([1-9][0-9]{0,3}|0)(\.([1-9][0-9]{0,3}|0)){5,13}$")
|
||||||
URL_VERIFY = re.compile(
|
URL_VERIFY = re.compile(r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+")
|
||||||
r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]"
|
|
||||||
+ r"|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+"
|
|
||||||
)
|
|
||||||
DN_VERIFY = re.compile(
|
DN_VERIFY = re.compile(
|
||||||
r"^(?:(?P<cn>CN=(?P<name>[^,]*)),)"
|
r"^(?:(?P<cn>CN=(?P<name>[^,]*)),)?(?:(?P<path>(?:(?:CN|OU)=[^,]+,?)+),)?(?P<domain>(?:DC=[^,]+,?)+)$"
|
||||||
+ r"?(?:(?P<path>(?:(?:CN|OU)=[^,]+,?)+),)"
|
|
||||||
+ r"?(?P<domain>(?:DC=[^,]+,?)+)$"
|
|
||||||
)
|
)
|
||||||
ULID_VERIFY = re.compile(r"^[0-9a-z]{26}$", re.IGNORECASE)
|
ULID_VERIFY = re.compile(r"^[0-9a-z]{26}$", re.IGNORECASE)
|
||||||
UUID_VERIFY = re.compile(
|
UUID_VERIFY = re.compile(
|
||||||
(
|
r"[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$",
|
||||||
"[a-f0-9]{8}-"
|
|
||||||
+ "[a-f0-9]{4}-"
|
|
||||||
+ "[1-5]"
|
|
||||||
+ "[a-f0-9]{3}-"
|
|
||||||
+ "[89ab][a-f0-9]{3}-"
|
|
||||||
+ "[a-f0-9]{12}$"
|
|
||||||
),
|
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,9 +40,8 @@ invites = re.compile(
|
||||||
UUID_GET = {3: uuidpy.uuid3, 5: uuidpy.uuid5}
|
UUID_GET = {3: uuidpy.uuid3, 5: uuidpy.uuid5}
|
||||||
|
|
||||||
|
|
||||||
def hash_obj(hash, data, text: bool = True) -> str:
|
def hash_obj(hash: Any, data: Union[str, bytes], text: bool = True) -> str:
|
||||||
"""
|
"""Hash data with hash object.
|
||||||
Hash data with hash object
|
|
||||||
|
|
||||||
Data can be text or binary
|
Data can be text or binary
|
||||||
"""
|
"""
|
||||||
|
@ -60,14 +51,16 @@ def hash_obj(hash, data, text: bool = True) -> str:
|
||||||
BSIZE = 65536
|
BSIZE = 65536
|
||||||
block_idx = 0
|
block_idx = 0
|
||||||
while block_idx * BSIZE < len(data):
|
while block_idx * BSIZE < len(data):
|
||||||
block = data[BSIZE * block_idx : BSIZE * (block_idx + 1)]
|
block = data[BSIZE * block_idx : BSIZE * (block_idx + 1)] # noqa: E203
|
||||||
hash.update(block)
|
hash.update(block)
|
||||||
block_idx += 1
|
block_idx += 1
|
||||||
return hash.hexdigest()
|
return hash.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
class DevCog(commands.Cog):
|
class DevCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Developer Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -79,9 +72,7 @@ class DevCog(commands.Cog):
|
||||||
description="Hash method",
|
description="Hash method",
|
||||||
option_type=3,
|
option_type=3,
|
||||||
required=True,
|
required=True,
|
||||||
choices=[
|
choices=[create_choice(name=x, value=x) for x in supported_hashes],
|
||||||
create_choice(name=x, value=x) for x in supported_hashes
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
create_option(
|
create_option(
|
||||||
name="data",
|
name="data",
|
||||||
|
@ -92,7 +83,7 @@ class DevCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _hash(self, ctx, method: str, data: str):
|
async def _hash(self, ctx: SlashContext, method: str, data: str) -> None:
|
||||||
if not data:
|
if not data:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"No data to hash",
|
"No data to hash",
|
||||||
|
@ -111,9 +102,7 @@ class DevCog(commands.Cog):
|
||||||
Field("Hash", f"`{hex}`", False),
|
Field("Hash", f"`{hex}`", False),
|
||||||
]
|
]
|
||||||
|
|
||||||
embed = build_embed(
|
embed = build_embed(title=title, description=description, fields=fields)
|
||||||
title=title, description=description, fields=fields
|
|
||||||
)
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -125,9 +114,7 @@ class DevCog(commands.Cog):
|
||||||
description="UUID version",
|
description="UUID version",
|
||||||
option_type=3,
|
option_type=3,
|
||||||
required=True,
|
required=True,
|
||||||
choices=[
|
choices=[create_choice(name=x, value=x) for x in ["3", "4", "5"]],
|
||||||
create_choice(name=x, value=x) for x in ["3", "4", "5"]
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
create_option(
|
create_option(
|
||||||
name="data",
|
name="data",
|
||||||
|
@ -137,7 +124,7 @@ class DevCog(commands.Cog):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _uuid(self, ctx, version: str, data: str = None):
|
async def _uuid(self, ctx: SlashContext, version: str, data: str = None) -> None:
|
||||||
version = int(version)
|
version = int(version)
|
||||||
if version in [3, 5] and not data:
|
if version in [3, 5] and not data:
|
||||||
await ctx.send(f"UUID{version} requires data.", hidden=True)
|
await ctx.send(f"UUID{version} requires data.", hidden=True)
|
||||||
|
@ -161,8 +148,7 @@ class DevCog(commands.Cog):
|
||||||
description="Generate an ObjectID",
|
description="Generate an ObjectID",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _objectid(self, ctx):
|
async def _objectid(self, ctx: SlashContext) -> None:
|
||||||
"""Generates new bson.ObjectId"""
|
|
||||||
await ctx.send(f"ObjectId: `{str(ObjectId())}`")
|
await ctx.send(f"ObjectId: `{str(ObjectId())}`")
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -170,8 +156,7 @@ class DevCog(commands.Cog):
|
||||||
description="Generate a ULID",
|
description="Generate a ULID",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _ulid(self, ctx):
|
async def _ulid(self, ctx: SlashContext) -> None:
|
||||||
"""Generates a new ULID"""
|
|
||||||
await ctx.send(f"ULID: `{ulidpy.new().str}`")
|
await ctx.send(f"ULID: `{ulidpy.new().str}`")
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -179,8 +164,7 @@ class DevCog(commands.Cog):
|
||||||
description="Convert a UUID to a ULID",
|
description="Convert a UUID to a ULID",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _uuid2ulid(self, ctx: commands.Context, uuid):
|
async def _uuid2ulid(self, ctx: SlashContext, uuid: str) -> None:
|
||||||
"""Converts a UUID to a ULID"""
|
|
||||||
if UUID_VERIFY.match(uuid):
|
if UUID_VERIFY.match(uuid):
|
||||||
u = ulidpy.parse(uuid)
|
u = ulidpy.parse(uuid)
|
||||||
await ctx.send(f"ULID: `{u.str}`")
|
await ctx.send(f"ULID: `{u.str}`")
|
||||||
|
@ -192,8 +176,7 @@ class DevCog(commands.Cog):
|
||||||
description="Convert a ULID to a UUID",
|
description="Convert a ULID to a UUID",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||||
async def _ulid2uuid(self, ctx: commands.Context, ulid):
|
async def _ulid2uuid(self, ctx: SlashContext, ulid: str) -> None:
|
||||||
"""Converts a ULID to a UUID"""
|
|
||||||
if ULID_VERIFY.match(ulid):
|
if ULID_VERIFY.match(ulid):
|
||||||
ulid = ulidpy.parse(ulid)
|
ulid = ulidpy.parse(ulid)
|
||||||
await ctx.send(f"UUID: `{ulid.uuid}`")
|
await ctx.send(f"UUID: `{ulid.uuid}`")
|
||||||
|
@ -211,9 +194,7 @@ class DevCog(commands.Cog):
|
||||||
description="Encode method",
|
description="Encode method",
|
||||||
option_type=3,
|
option_type=3,
|
||||||
required=True,
|
required=True,
|
||||||
choices=[
|
choices=[create_choice(name=x, value=x) for x in base64_methods],
|
||||||
create_choice(name=x, value=x) for x in base64_methods
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
create_option(
|
create_option(
|
||||||
name="data",
|
name="data",
|
||||||
|
@ -223,8 +204,7 @@ class DevCog(commands.Cog):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _encode(self, ctx, method: str, data: str):
|
async def _encode(self, ctx: SlashContext, method: str, data: str) -> None:
|
||||||
"""Encodes text with specified encoding method"""
|
|
||||||
method = getattr(base64, method + "encode")
|
method = getattr(base64, method + "encode")
|
||||||
await ctx.send(f"`{method(data.encode('UTF-8')).decode('UTF-8')}`")
|
await ctx.send(f"`{method(data.encode('UTF-8')).decode('UTF-8')}`")
|
||||||
|
|
||||||
|
@ -237,9 +217,7 @@ class DevCog(commands.Cog):
|
||||||
description="Decode method",
|
description="Decode method",
|
||||||
option_type=3,
|
option_type=3,
|
||||||
required=True,
|
required=True,
|
||||||
choices=[
|
choices=[create_choice(name=x, value=x) for x in base64_methods],
|
||||||
create_choice(name=x, value=x) for x in base64_methods
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
create_option(
|
create_option(
|
||||||
name="data",
|
name="data",
|
||||||
|
@ -249,8 +227,7 @@ class DevCog(commands.Cog):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _decode(self, ctx, method: str, data: str):
|
async def _decode(self, ctx: SlashContext, method: str, data: str) -> None:
|
||||||
"""Decodes text with specified encoding method"""
|
|
||||||
method = getattr(base64, method + "decode")
|
method = getattr(base64, method + "decode")
|
||||||
decoded = method(data.encode("UTF-8")).decode("UTF-8")
|
decoded = method(data.encode("UTF-8")).decode("UTF-8")
|
||||||
if invites.search(decoded):
|
if invites.search(decoded):
|
||||||
|
@ -266,12 +243,11 @@ class DevCog(commands.Cog):
|
||||||
description="Get J.A.R.V.I.S. lines of code",
|
description="Get J.A.R.V.I.S. lines of code",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _cloc(self, ctx):
|
async def _cloc(self, ctx: SlashContext) -> None:
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output(["tokei", "-C", "--sort", "code"]).decode("UTF-8") # noqa: S603, S607
|
||||||
["tokei", "-C", "--sort", "code"]
|
|
||||||
).decode("UTF-8")
|
|
||||||
await ctx.send(f"```\n{output}\n```")
|
await ctx.send(f"```\n{output}\n```")
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add DevCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(DevCog(bot))
|
bot.add_cog(DevCog(bot))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""J.A.R.V.I.S. error handling cog."""
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import SlashContext
|
from discord_slash import SlashContext
|
||||||
|
|
||||||
|
@ -5,36 +6,36 @@ from jarvis import slash
|
||||||
|
|
||||||
|
|
||||||
class ErrorHandlerCog(commands.Cog):
|
class ErrorHandlerCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. error handling cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_command_error(self, ctx: commands.Context, error):
|
async def on_command_error(self, ctx: commands.Context, error: Exception) -> None:
|
||||||
|
"""d.py on_command_error override."""
|
||||||
if isinstance(error, commands.errors.MissingPermissions):
|
if isinstance(error, commands.errors.MissingPermissions):
|
||||||
await ctx.send("I'm afraid I can't let you do that.")
|
await ctx.send("I'm afraid I can't let you do that.")
|
||||||
elif isinstance(error, commands.errors.CommandNotFound):
|
elif isinstance(error, commands.errors.CommandNotFound):
|
||||||
return
|
return
|
||||||
elif isinstance(error, commands.errors.CommandOnCooldown):
|
elif isinstance(error, commands.errors.CommandOnCooldown):
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Command on cooldown. "
|
"Command on cooldown. " + f"Please wait {error.retry_after:0.2f}s before trying again",
|
||||||
+ f"Please wait {error.retry_after:0.2f}s before trying again",
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await ctx.send(f"Error processing command:\n```{error}```")
|
await ctx.send(f"Error processing command:\n```{error}```")
|
||||||
ctx.command.reset_cooldown(ctx)
|
ctx.command.reset_cooldown(ctx)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_slash_command_error(self, ctx: SlashContext, error):
|
async def on_slash_command_error(self, ctx: SlashContext, error: Exception) -> None:
|
||||||
if isinstance(error, commands.errors.MissingPermissions) or isinstance(
|
"""discord_slash on_slash_command_error override."""
|
||||||
error, commands.errors.CheckFailure
|
if isinstance(error, commands.errors.MissingPermissions) or isinstance(error, commands.errors.CheckFailure):
|
||||||
):
|
|
||||||
await ctx.send("I'm afraid I can't let you do that.", hidden=True)
|
await ctx.send("I'm afraid I can't let you do that.", hidden=True)
|
||||||
elif isinstance(error, commands.errors.CommandNotFound):
|
elif isinstance(error, commands.errors.CommandNotFound):
|
||||||
return
|
return
|
||||||
elif isinstance(error, commands.errors.CommandOnCooldown):
|
elif isinstance(error, commands.errors.CommandOnCooldown):
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Command on cooldown. "
|
"Command on cooldown. " + f"Please wait {error.retry_after:0.2f}s before trying again",
|
||||||
+ f"Please wait {error.retry_after:0.2f}s before trying again",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -45,5 +46,6 @@ class ErrorHandlerCog(commands.Cog):
|
||||||
slash.commands[ctx.command].reset_cooldown(ctx)
|
slash.commands[ctx.command].reset_cooldown(ctx)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add ErrorHandlerCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(ErrorHandlerCog(bot))
|
bot.add_cog(ErrorHandlerCog(bot))
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. GitLab Cog."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import gitlab
|
import gitlab
|
||||||
from ButtonPaginator import Paginator
|
from ButtonPaginator import Paginator
|
||||||
|
from discord import Embed
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.ext.tasks import loop
|
from discord_slash import cog_ext
|
||||||
from discord.utils import find
|
from discord_slash import SlashContext
|
||||||
from discord_slash import SlashContext, cog_ext
|
|
||||||
from discord_slash.model import ButtonStyle
|
from discord_slash.model import ButtonStyle
|
||||||
from discord_slash.utils.manage_commands import create_choice, create_option
|
from discord_slash.utils.manage_commands import create_choice
|
||||||
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
|
@ -18,12 +21,12 @@ guild_ids = [862402786116763668]
|
||||||
|
|
||||||
|
|
||||||
class GitlabCog(CacheCog):
|
class GitlabCog(CacheCog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. GitLab Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
config = get_config()
|
config = get_config()
|
||||||
self._gitlab = gitlab.Gitlab(
|
self._gitlab = gitlab.Gitlab("https://git.zevaryx.com", private_token=config.gitlab_token)
|
||||||
"https://git.zevaryx.com", private_token=config.gitlab_token
|
|
||||||
)
|
|
||||||
# J.A.R.V.I.S. GitLab ID is 29
|
# J.A.R.V.I.S. GitLab ID is 29
|
||||||
self.project = self._gitlab.projects.get(29)
|
self.project = self._gitlab.projects.get(29)
|
||||||
|
|
||||||
|
@ -32,13 +35,9 @@ class GitlabCog(CacheCog):
|
||||||
name="issue",
|
name="issue",
|
||||||
description="Get an issue from GitLab",
|
description="Get an issue from GitLab",
|
||||||
guild_ids=guild_ids,
|
guild_ids=guild_ids,
|
||||||
options=[
|
options=[create_option(name="id", description="Issue ID", option_type=4, required=True)],
|
||||||
create_option(
|
|
||||||
name="id", description="Issue ID", option_type=4, required=True
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
async def _issue(self, ctx: SlashContext, id: int):
|
async def _issue(self, ctx: SlashContext, id: int) -> None:
|
||||||
try:
|
try:
|
||||||
issue = self.project.issues.get(int(id))
|
issue = self.project.issues.get(int(id))
|
||||||
except gitlab.exceptions.GitlabGetError:
|
except gitlab.exceptions.GitlabGetError:
|
||||||
|
@ -50,9 +49,7 @@ class GitlabCog(CacheCog):
|
||||||
else:
|
else:
|
||||||
assignee = "None"
|
assignee = "None"
|
||||||
|
|
||||||
created_at = datetime.strptime(
|
created_at = datetime.strptime(issue.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
issue.created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
|
|
||||||
labels = issue.labels
|
labels = issue.labels
|
||||||
if labels:
|
if labels:
|
||||||
|
@ -61,25 +58,20 @@ class GitlabCog(CacheCog):
|
||||||
labels = "None"
|
labels = "None"
|
||||||
|
|
||||||
fields = [
|
fields = [
|
||||||
Field(
|
Field(name="State", value=issue.state[0].upper() + issue.state[1:]),
|
||||||
name="State", value=issue.state[0].upper() + issue.state[1:]
|
|
||||||
),
|
|
||||||
Field(name="Assignee", value=assignee),
|
Field(name="Assignee", value=assignee),
|
||||||
Field(name="Labels", value=labels),
|
Field(name="Labels", value=labels),
|
||||||
]
|
]
|
||||||
color = self.project.labels.get(issue.labels[0]).color
|
color = self.project.labels.get(issue.labels[0]).color
|
||||||
fields.append(Field(name="Created At", value=created_at))
|
fields.append(Field(name="Created At", value=created_at))
|
||||||
if issue.state == "closed":
|
if issue.state == "closed":
|
||||||
closed_at = datetime.strptime(
|
closed_at = datetime.strptime(issue.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
issue.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
fields.append(Field(name="Closed At", value=closed_at))
|
fields.append(Field(name="Closed At", value=closed_at))
|
||||||
if issue.milestone:
|
if issue.milestone:
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name="Milestone",
|
name="Milestone",
|
||||||
value=f"[{issue.milestone['title']}]"
|
value=f"[{issue.milestone['title']}]({issue.milestone['web_url']})",
|
||||||
+ f"({issue.milestone['web_url']})",
|
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -97,10 +89,7 @@ class GitlabCog(CacheCog):
|
||||||
icon_url=issue.author["avatar_url"],
|
icon_url=issue.author["avatar_url"],
|
||||||
url=issue.author["web_url"],
|
url=issue.author["web_url"],
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(
|
embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
|
||||||
url="https://about.gitlab.com/images"
|
|
||||||
+ "/press/logo/png/gitlab-icon-rgb.png"
|
|
||||||
)
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -117,16 +106,14 @@ class GitlabCog(CacheCog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _milestone(self, ctx: SlashContext, id: int):
|
async def _milestone(self, ctx: SlashContext, id: int) -> None:
|
||||||
try:
|
try:
|
||||||
milestone = self.project.milestones.get(int(id))
|
milestone = self.project.milestones.get(int(id))
|
||||||
except gitlab.exceptions.GitlabGetError:
|
except gitlab.exceptions.GitlabGetError:
|
||||||
await ctx.send("Milestone does not exist.", hidden=True)
|
await ctx.send("Milestone does not exist.", hidden=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
created_at = datetime.strptime(
|
created_at = datetime.strptime(milestone.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
milestone.created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
|
|
||||||
fields = [
|
fields = [
|
||||||
Field(
|
Field(
|
||||||
|
@ -139,9 +126,9 @@ class GitlabCog(CacheCog):
|
||||||
]
|
]
|
||||||
|
|
||||||
if milestone.updated_at:
|
if milestone.updated_at:
|
||||||
updated_at = datetime.strptime(
|
updated_at = datetime.strptime(milestone.updated_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime(
|
||||||
milestone.updated_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
"%Y-%m-%d %H:%M:%S UTC"
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
)
|
||||||
fields.append(Field(name="Updated At", value=updated_at))
|
fields.append(Field(name="Updated At", value=updated_at))
|
||||||
|
|
||||||
if len(milestone.title) > 200:
|
if len(milestone.title) > 200:
|
||||||
|
@ -157,13 +144,9 @@ class GitlabCog(CacheCog):
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name="J.A.R.V.I.S.",
|
name="J.A.R.V.I.S.",
|
||||||
url="https://git.zevaryx.com/jarvis",
|
url="https://git.zevaryx.com/jarvis",
|
||||||
icon_url="https://git.zevaryx.com/uploads/-"
|
icon_url="https://git.zevaryx.com/uploads/-/system/user/avatar/11/avatar.png",
|
||||||
+ "/system/user/avatar/11/avatar.png",
|
|
||||||
)
|
|
||||||
embed.set_thumbnail(
|
|
||||||
url="https://about.gitlab.com/images"
|
|
||||||
+ "/press/logo/png/gitlab-icon-rgb.png"
|
|
||||||
)
|
)
|
||||||
|
embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -180,7 +163,7 @@ class GitlabCog(CacheCog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _mergerequest(self, ctx: SlashContext, id: int):
|
async def _mergerequest(self, ctx: SlashContext, id: int) -> None:
|
||||||
try:
|
try:
|
||||||
mr = self.project.mergerequests.get(int(id))
|
mr = self.project.mergerequests.get(int(id))
|
||||||
except gitlab.exceptions.GitlabGetError:
|
except gitlab.exceptions.GitlabGetError:
|
||||||
|
@ -192,9 +175,7 @@ class GitlabCog(CacheCog):
|
||||||
else:
|
else:
|
||||||
assignee = "None"
|
assignee = "None"
|
||||||
|
|
||||||
created_at = datetime.strptime(
|
created_at = datetime.strptime(mr.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
mr.created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
|
|
||||||
labels = mr.labels
|
labels = mr.labels
|
||||||
if labels:
|
if labels:
|
||||||
|
@ -213,21 +194,16 @@ class GitlabCog(CacheCog):
|
||||||
color = "#00FFEE"
|
color = "#00FFEE"
|
||||||
fields.append(Field(name="Created At", value=created_at))
|
fields.append(Field(name="Created At", value=created_at))
|
||||||
if mr.state == "merged":
|
if mr.state == "merged":
|
||||||
merged_at = datetime.strptime(
|
merged_at = datetime.strptime(mr.merged_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
mr.merged_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
fields.append(Field(name="Merged At", value=merged_at))
|
fields.append(Field(name="Merged At", value=merged_at))
|
||||||
elif mr.state == "closed":
|
elif mr.state == "closed":
|
||||||
closed_at = datetime.strptime(
|
closed_at = datetime.strptime(mr.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
mr.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
fields.append(Field(name="Closed At", value=closed_at))
|
fields.append(Field(name="Closed At", value=closed_at))
|
||||||
if mr.milestone:
|
if mr.milestone:
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name="Milestone",
|
name="Milestone",
|
||||||
value=f"[{mr.milestone['title']}]"
|
value=f"[{mr.milestone['title']}]({mr.milestone['web_url']})",
|
||||||
+ f"({mr.milestone['web_url']})",
|
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -245,13 +221,11 @@ class GitlabCog(CacheCog):
|
||||||
icon_url=mr.author["avatar_url"],
|
icon_url=mr.author["avatar_url"],
|
||||||
url=mr.author["web_url"],
|
url=mr.author["web_url"],
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(
|
embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
|
||||||
url="https://about.gitlab.com/images"
|
|
||||||
+ "/press/logo/png/gitlab-icon-rgb.png"
|
|
||||||
)
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
def build_embed_page(self, api_list: list, t_state: str, name: str):
|
def build_embed_page(self, api_list: list, t_state: str, name: str) -> Embed:
|
||||||
|
"""Build an embed page for the paginator."""
|
||||||
title = ""
|
title = ""
|
||||||
if t_state:
|
if t_state:
|
||||||
title = f"{t_state} "
|
title = f"{t_state} "
|
||||||
|
@ -261,8 +235,7 @@ class GitlabCog(CacheCog):
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name=f"[#{item.iid}] {item.title}",
|
name=f"[#{item.iid}] {item.title}",
|
||||||
value=item.description
|
value=item.description + f"\n\n[View this {name}]({item.web_url})",
|
||||||
+ f"\n\n[View this {name}]({item.web_url})",
|
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -271,19 +244,14 @@ class GitlabCog(CacheCog):
|
||||||
title=title,
|
title=title,
|
||||||
description="",
|
description="",
|
||||||
fields=fields,
|
fields=fields,
|
||||||
url="https://git.zevaryx.com/stark-industries/j.a.r.v.i.s./"
|
url=f"https://git.zevaryx.com/stark-industries/j.a.r.v.i.s./{name.replace(' ', '_')}s",
|
||||||
+ f"{name.replace(' ', '_')}s",
|
|
||||||
)
|
)
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name="J.A.R.V.I.S.",
|
name="J.A.R.V.I.S.",
|
||||||
url="https://git.zevaryx.com/jarvis",
|
url="https://git.zevaryx.com/jarvis",
|
||||||
icon_url="https://git.zevaryx.com/uploads/-"
|
icon_url="https://git.zevaryx.com/uploads/-/system/user/avatar/11/avatar.png",
|
||||||
+ "/system/user/avatar/11/avatar.png",
|
|
||||||
)
|
|
||||||
embed.set_thumbnail(
|
|
||||||
url="https://about.gitlab.com/images"
|
|
||||||
+ "/press/logo/png/gitlab-icon-rgb.png"
|
|
||||||
)
|
)
|
||||||
|
embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -305,13 +273,12 @@ class GitlabCog(CacheCog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _issues(self, ctx: SlashContext, state: str = "opened"):
|
async def _issues(self, ctx: SlashContext, state: str = "opened") -> None:
|
||||||
exists = self.check_cache(ctx, state=state)
|
exists = self.check_cache(ctx, state=state)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
"Please use existing interaction: " + f"{exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -347,11 +314,7 @@ class GitlabCog(CacheCog):
|
||||||
pages = []
|
pages = []
|
||||||
t_state = t_state[0].upper() + t_state[1:]
|
t_state = t_state[0].upper() + t_state[1:]
|
||||||
for i in range(0, len(issues), 5):
|
for i in range(0, len(issues), 5):
|
||||||
pages.append(
|
pages.append(self.build_embed_page(issues[i : i + 5], t_state=t_state, name="issue")) # noqa: E203
|
||||||
self.build_embed_page(
|
|
||||||
issues[i : i + 5], t_state=t_state, name="issue"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
paginator = Paginator(
|
paginator = Paginator(
|
||||||
bot=self.bot,
|
bot=self.bot,
|
||||||
|
@ -397,13 +360,12 @@ class GitlabCog(CacheCog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _mergerequests(self, ctx: SlashContext, state: str = "opened"):
|
async def _mergerequests(self, ctx: SlashContext, state: str = "opened") -> None:
|
||||||
exists = self.check_cache(ctx, state=state)
|
exists = self.check_cache(ctx, state=state)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
"Please use existing interaction: " + f"{exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -439,11 +401,7 @@ class GitlabCog(CacheCog):
|
||||||
pages = []
|
pages = []
|
||||||
t_state = t_state[0].upper() + t_state[1:]
|
t_state = t_state[0].upper() + t_state[1:]
|
||||||
for i in range(0, len(merges), 5):
|
for i in range(0, len(merges), 5):
|
||||||
pages.append(
|
pages.append(self.build_embed_page(merges[i : i + 5], t_state=t_state, name="merge request")) # noqa: E203
|
||||||
self.build_embed_page(
|
|
||||||
merges[i : i + 5], t_state=t_state, name="merge request"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
paginator = Paginator(
|
paginator = Paginator(
|
||||||
bot=self.bot,
|
bot=self.bot,
|
||||||
|
@ -475,13 +433,12 @@ class GitlabCog(CacheCog):
|
||||||
description="Get open issues from GitLab",
|
description="Get open issues from GitLab",
|
||||||
guild_ids=guild_ids,
|
guild_ids=guild_ids,
|
||||||
)
|
)
|
||||||
async def _milestones(self, ctx: SlashContext):
|
async def _milestones(self, ctx: SlashContext) -> None:
|
||||||
exists = self.check_cache(ctx)
|
exists = self.check_cache(ctx)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -509,11 +466,7 @@ class GitlabCog(CacheCog):
|
||||||
|
|
||||||
pages = []
|
pages = []
|
||||||
for i in range(0, len(milestones), 5):
|
for i in range(0, len(milestones), 5):
|
||||||
pages.append(
|
pages.append(self.build_embed_page(milestones[i : i + 5], t_state=None, name="milestone")) # noqa: E203
|
||||||
self.build_embed_page(
|
|
||||||
milestones[i : i + 5], t_state=None, name="milestone"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
paginator = Paginator(
|
paginator = Paginator(
|
||||||
bot=self.bot,
|
bot=self.bot,
|
||||||
|
@ -539,6 +492,7 @@ class GitlabCog(CacheCog):
|
||||||
await paginator.start()
|
await paginator.start()
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add GitlabCog to J.A.R.V.I.S. if Gitlab token exists."""
|
||||||
if get_config().gitlab_token:
|
if get_config().gitlab_token:
|
||||||
bot.add_cog(GitlabCog(bot))
|
bot.add_cog(GitlabCog(bot))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""J.A.R.V.I.S. image processing cog."""
|
||||||
import re
|
import re
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
@ -7,7 +8,9 @@ import numpy as np
|
||||||
from discord import File
|
from discord import File
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
from jarvis.utils import build_embed, convert_bytesize, unconvert_bytesize
|
from jarvis.utils import build_embed
|
||||||
|
from jarvis.utils import convert_bytesize
|
||||||
|
from jarvis.utils import unconvert_bytesize
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,38 +21,31 @@ class ImageCog(commands.Cog):
|
||||||
May be categorized under util later
|
May be categorized under util later
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self._session = aiohttp.ClientSession()
|
self._session = aiohttp.ClientSession()
|
||||||
self.tgt_match = re.compile(
|
self.tgt_match = re.compile(r"([0-9]*\.?[0-9]*?) ?([KMGTP]?B)", re.IGNORECASE)
|
||||||
r"([0-9]*\.?[0-9]*?) ?([KMGTP]?B)", re.IGNORECASE
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _resize(self, ctx, target: str, url: str = None):
|
def __del__(self):
|
||||||
|
self._session.close()
|
||||||
|
|
||||||
|
async def _resize(self, ctx: commands.Context, target: str, url: str = None) -> None:
|
||||||
if not target:
|
if not target:
|
||||||
await ctx.send("Missing target size, i.e. 200KB.")
|
await ctx.send("Missing target size, i.e. 200KB.")
|
||||||
return
|
return
|
||||||
|
|
||||||
tgt = self.tgt_match.match(target)
|
tgt = self.tgt_match.match(target)
|
||||||
if not tgt:
|
if not tgt:
|
||||||
await ctx.send(
|
await ctx.send(f"Invalid target format ({target}). Expected format like 200KB")
|
||||||
"Invalid target format ({}).".format(target)
|
|
||||||
+ " Expected format like 200KB"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
tgt_size = unconvert_bytesize(float(tgt.groups()[0]), tgt.groups()[1])
|
tgt_size = unconvert_bytesize(float(tgt.groups()[0]), tgt.groups()[1])
|
||||||
if tgt_size > unconvert_bytesize(8, "MB"):
|
if tgt_size > unconvert_bytesize(8, "MB"):
|
||||||
await ctx.send(
|
await ctx.send("Target too large to send. Please make target < 8MB")
|
||||||
"Target too large to send. Please make target < 8MB"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
file = None
|
file = None
|
||||||
filename = None
|
filename = None
|
||||||
if (
|
if ctx.message.attachments is not None and len(ctx.message.attachments) > 0:
|
||||||
ctx.message.attachments is not None
|
|
||||||
and len(ctx.message.attachments) > 0
|
|
||||||
):
|
|
||||||
file = await ctx.message.attachments[0].read()
|
file = await ctx.message.attachments[0].read()
|
||||||
filename = ctx.message.attachments[0].filename
|
filename = ctx.message.attachments[0].filename
|
||||||
elif url is not None:
|
elif url is not None:
|
||||||
|
@ -69,9 +65,7 @@ class ImageCog(commands.Cog):
|
||||||
|
|
||||||
accuracy = 0.0
|
accuracy = 0.0
|
||||||
# TODO: Optimize to not run multiple times
|
# TODO: Optimize to not run multiple times
|
||||||
while len(file) > tgt_size or (
|
while len(file) > tgt_size or (len(file) <= tgt_size and accuracy < 0.65):
|
||||||
len(file) <= tgt_size and accuracy < 0.65
|
|
||||||
):
|
|
||||||
old_file = file
|
old_file = file
|
||||||
|
|
||||||
buffer = np.frombuffer(file, dtype=np.uint8)
|
buffer = np.frombuffer(file, dtype=np.uint8)
|
||||||
|
@ -105,9 +99,10 @@ class ImageCog(commands.Cog):
|
||||||
|
|
||||||
@commands.command(name="resize", help="Resize an image")
|
@commands.command(name="resize", help="Resize an image")
|
||||||
@commands.cooldown(1, 60, commands.BucketType.user)
|
@commands.cooldown(1, 60, commands.BucketType.user)
|
||||||
async def _resize_pref(self, ctx, target: str, url: str = None):
|
async def _resize_pref(self, ctx: commands.Context, target: str, url: str = None) -> None:
|
||||||
await self._resize(ctx, target, url)
|
await self._resize(ctx, target, url)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add ImageCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(ImageCog(bot))
|
bot.add_cog(ImageCog(bot))
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
|
"""J.A.R.V.I.S. Jokes module."""
|
||||||
import html
|
import html
|
||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from random import randint
|
from secrets import randint
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
|
|
||||||
import jarvis
|
|
||||||
from jarvis.db.models import Joke
|
from jarvis.db.models import Joke
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
@ -20,11 +21,17 @@ class JokeCog(commands.Cog):
|
||||||
May adapt over time to create jokes using machine learning
|
May adapt over time to create jokes using machine learning
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
# TODO: Make this a command group with subcommands
|
# TODO: Make this a command group with subcommands
|
||||||
async def _joke(self, ctx, id: str = None):
|
@cog_ext.cog_slash(
|
||||||
|
name="joke",
|
||||||
|
description="Hear a joke",
|
||||||
|
)
|
||||||
|
@commands.cooldown(1, 10, commands.BucketType.channel)
|
||||||
|
async def _joke(self, ctx: SlashContext, id: str = None) -> None:
|
||||||
|
"""Get a joke from the database."""
|
||||||
try:
|
try:
|
||||||
if randint(1, 100_000) == 5779 and id is None:
|
if randint(1, 100_000) == 5779 and id is None:
|
||||||
await ctx.send(f"<@{ctx.message.author.id}>")
|
await ctx.send(f"<@{ctx.message.author.id}>")
|
||||||
|
@ -44,20 +51,14 @@ class JokeCog(commands.Cog):
|
||||||
result = Joke.objects().aggregate(pipeline).next()
|
result = Joke.objects().aggregate(pipeline).next()
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
await ctx.send(
|
await ctx.send("Humor module failed. Please try again later.", hidden=True)
|
||||||
"Humor module failed. Please try again later.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
emotes = re.findall(r"(&#x[a-fA-F0-9]*;)", result["body"])
|
emotes = re.findall(r"(&#x[a-fA-F0-9]*;)", result["body"])
|
||||||
for match in emotes:
|
for match in emotes:
|
||||||
result["body"] = result["body"].replace(
|
result["body"] = result["body"].replace(match, html.unescape(match))
|
||||||
match, html.unescape(match)
|
|
||||||
)
|
|
||||||
emotes = re.findall(r"(&#x[a-fA-F0-9]*;)", result["title"])
|
emotes = re.findall(r"(&#x[a-fA-F0-9]*;)", result["title"])
|
||||||
for match in emotes:
|
for match in emotes:
|
||||||
result["title"] = result["title"].replace(
|
result["title"] = result["title"].replace(match, html.unescape(match))
|
||||||
match, html.unescape(match)
|
|
||||||
)
|
|
||||||
body_chunks = []
|
body_chunks = []
|
||||||
|
|
||||||
body = ""
|
body = ""
|
||||||
|
@ -105,19 +106,10 @@ class JokeCog(commands.Cog):
|
||||||
)
|
)
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
except Exception:
|
except Exception:
|
||||||
await ctx.send(
|
await ctx.send("Encountered error:\n```\n" + traceback.format_exc() + "\n```")
|
||||||
"Encountered error:\n```\n" + traceback.format_exc() + "\n```"
|
|
||||||
)
|
|
||||||
# await ctx.send(f"**{result['title']}**\n\n{result['body']}")
|
# await ctx.send(f"**{result['title']}**\n\n{result['body']}")
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
|
||||||
name="joke",
|
|
||||||
description="Hear a joke",
|
|
||||||
)
|
|
||||||
@commands.cooldown(1, 10, commands.BucketType.channel)
|
|
||||||
async def _joke_slash(self, ctx, id: str = None):
|
|
||||||
await self._joke(ctx, id)
|
|
||||||
|
|
||||||
|
def setup(bot: commands.Bot) -> None:
|
||||||
def setup(bot):
|
"""Add JokeCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(JokeCog(bot))
|
bot.add_cog(JokeCog(bot))
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
from jarvis.cogs.modlog import command, member, message
|
"""J.A.R.V.I.S. Modlog Cogs."""
|
||||||
|
from discord.ext.commands import Bot
|
||||||
|
|
||||||
|
from jarvis.cogs.modlog import command
|
||||||
|
from jarvis.cogs.modlog import member
|
||||||
|
from jarvis.cogs.modlog import message
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: Bot) -> None:
|
||||||
|
"""Add modlog cogs to J.A.R.V.I.S."""
|
||||||
bot.add_cog(command.ModlogCommandCog(bot))
|
bot.add_cog(command.ModlogCommandCog(bot))
|
||||||
bot.add_cog(member.ModlogMemberCog(bot))
|
bot.add_cog(member.ModlogMemberCog(bot))
|
||||||
bot.add_cog(message.ModlogMessageCog(bot))
|
bot.add_cog(message.ModlogMessageCog(bot))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""J.A.R.V.I.S. ModlogCommandCog."""
|
||||||
from discord import DMChannel
|
from discord import DMChannel
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import SlashContext
|
from discord_slash import SlashContext
|
||||||
|
@ -8,24 +9,23 @@ from jarvis.utils.field import Field
|
||||||
|
|
||||||
|
|
||||||
class ModlogCommandCog(commands.Cog):
|
class ModlogCommandCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. ModlogCommandCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_slash_command(self, ctx: SlashContext):
|
async def on_slash_command(self, ctx: SlashContext) -> None:
|
||||||
|
"""Process on_slash_command events."""
|
||||||
if not isinstance(ctx.channel, DMChannel) and ctx.name not in ["pw"]:
|
if not isinstance(ctx.channel, DMChannel) and ctx.name not in ["pw"]:
|
||||||
modlog = Setting.objects(
|
modlog = Setting.objects(guild=ctx.guild.id, setting="modlog").first()
|
||||||
guild=ctx.guild.id, setting="modlog"
|
|
||||||
).first()
|
|
||||||
if modlog:
|
if modlog:
|
||||||
channel = ctx.guild.get_channel(modlog.value)
|
channel = ctx.guild.get_channel(modlog.value)
|
||||||
fields = [
|
fields = [
|
||||||
Field("Command", ctx.name),
|
Field("Command", ctx.name),
|
||||||
]
|
]
|
||||||
if ctx.kwargs:
|
if ctx.kwargs:
|
||||||
kwargs_string = " ".join(
|
kwargs_string = " ".join(f"{k}: {str(ctx.kwargs[k])}" for k in ctx.kwargs)
|
||||||
f"{k}: {str(ctx.kwargs[k])}" for k in ctx.kwargs
|
|
||||||
)
|
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
"Keyword Args",
|
"Keyword Args",
|
||||||
|
@ -45,8 +45,5 @@ class ModlogCommandCog(commands.Cog):
|
||||||
name=ctx.author.name,
|
name=ctx.author.name,
|
||||||
icon_url=ctx.author.avatar_url,
|
icon_url=ctx.author.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{ctx.author.name}#{ctx.author.discriminator} | {ctx.author.id}")
|
||||||
text=f"{ctx.author.name}#{ctx.author.discriminator}"
|
|
||||||
+ f" | {ctx.author.id}"
|
|
||||||
)
|
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
|
@ -1,24 +1,34 @@
|
||||||
|
"""J.A.R.V.I.S. ModlogMemberCog."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
|
|
||||||
from jarvis.cogs.modlog.utils import get_latest_log, modlog_embed
|
from jarvis.cogs.modlog.utils import get_latest_log
|
||||||
|
from jarvis.cogs.modlog.utils import modlog_embed
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
from jarvis.db.models import Ban, Kick, Mute, Setting, Unban
|
from jarvis.db.models import Ban
|
||||||
|
from jarvis.db.models import Kick
|
||||||
|
from jarvis.db.models import Mute
|
||||||
|
from jarvis.db.models import Setting
|
||||||
|
from jarvis.db.models import Unban
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
|
||||||
|
|
||||||
class ModlogMemberCog(commands.Cog):
|
class ModlogMemberCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. ModlogMemberCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.cache = []
|
self.cache = []
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_member_ban(self, guild: discord.Guild, user: discord.User):
|
async def on_member_ban(self, guild: discord.Guild, user: discord.User) -> None:
|
||||||
|
"""Process on_member_ban events."""
|
||||||
modlog = Setting.objects(guild=guild.id, setting="modlog").first()
|
modlog = Setting.objects(guild=guild.id, setting="modlog").first()
|
||||||
if modlog:
|
if modlog:
|
||||||
channel = guild.get_channel(modlog.value)
|
channel = guild.get_channel(modlog.value)
|
||||||
|
@ -55,7 +65,8 @@ class ModlogMemberCog(commands.Cog):
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_member_unban(self, guild: discord.Guild, user: discord.User):
|
async def on_member_unban(self, guild: discord.Guild, user: discord.User) -> None:
|
||||||
|
"""Process on_member_unban events."""
|
||||||
modlog = Setting.objects(guild=guild.id, setting="modlog").first()
|
modlog = Setting.objects(guild=guild.id, setting="modlog").first()
|
||||||
if modlog:
|
if modlog:
|
||||||
channel = guild.get_channel(modlog.value)
|
channel = guild.get_channel(modlog.value)
|
||||||
|
@ -90,7 +101,8 @@ class ModlogMemberCog(commands.Cog):
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_member_remove(self, user: discord.Member):
|
async def on_member_remove(self, user: discord.Member) -> None:
|
||||||
|
"""Process on_member_remove events."""
|
||||||
modlog = Setting.objects(guild=user.guild.id, setting="modlog").first()
|
modlog = Setting.objects(guild=user.guild.id, setting="modlog").first()
|
||||||
if modlog:
|
if modlog:
|
||||||
channel = user.guild.get_channel(modlog.value)
|
channel = user.guild.get_channel(modlog.value)
|
||||||
|
@ -134,7 +146,8 @@ class ModlogMemberCog(commands.Cog):
|
||||||
|
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
async def process_mute(self, before, after) -> discord.Embed:
|
async def process_mute(self, before: discord.Member, after: discord.Member) -> discord.Embed:
|
||||||
|
"""Process mute event."""
|
||||||
await asyncio.sleep(0.5) # Need to wait for audit log
|
await asyncio.sleep(0.5) # Need to wait for audit log
|
||||||
auditlog = await before.guild.audit_logs(
|
auditlog = await before.guild.audit_logs(
|
||||||
limit=50,
|
limit=50,
|
||||||
|
@ -165,7 +178,8 @@ class ModlogMemberCog(commands.Cog):
|
||||||
desc=f"{before.mention} was muted",
|
desc=f"{before.mention} was muted",
|
||||||
)
|
)
|
||||||
|
|
||||||
async def process_unmute(self, before, after) -> discord.Embed:
|
async def process_unmute(self, before: discord.Member, after: discord.Member) -> discord.Embed:
|
||||||
|
"""Process unmute event."""
|
||||||
await asyncio.sleep(0.5) # Need to wait for audit log
|
await asyncio.sleep(0.5) # Need to wait for audit log
|
||||||
auditlog = await before.guild.audit_logs(
|
auditlog = await before.guild.audit_logs(
|
||||||
limit=50,
|
limit=50,
|
||||||
|
@ -196,7 +210,8 @@ class ModlogMemberCog(commands.Cog):
|
||||||
desc=f"{before.mention} was muted",
|
desc=f"{before.mention} was muted",
|
||||||
)
|
)
|
||||||
|
|
||||||
async def process_verify(self, before, after) -> discord.Embed:
|
async def process_verify(self, before: discord.Member, after: discord.Member) -> discord.Embed:
|
||||||
|
"""Process verification event."""
|
||||||
await asyncio.sleep(0.5) # Need to wait for audit log
|
await asyncio.sleep(0.5) # Need to wait for audit log
|
||||||
auditlog = await before.guild.audit_logs(
|
auditlog = await before.guild.audit_logs(
|
||||||
limit=50,
|
limit=50,
|
||||||
|
@ -214,7 +229,8 @@ class ModlogMemberCog(commands.Cog):
|
||||||
desc=f"{before.mention} was verified",
|
desc=f"{before.mention} was verified",
|
||||||
)
|
)
|
||||||
|
|
||||||
async def process_rolechange(self, before, after) -> discord.Embed:
|
async def process_rolechange(self, before: discord.Member, after: discord.Member) -> discord.Embed:
|
||||||
|
"""Process rolechange event."""
|
||||||
await asyncio.sleep(0.5) # Need to wait for audit log
|
await asyncio.sleep(0.5) # Need to wait for audit log
|
||||||
auditlog = await before.guild.audit_logs(
|
auditlog = await before.guild.audit_logs(
|
||||||
limit=50,
|
limit=50,
|
||||||
|
@ -243,50 +259,34 @@ class ModlogMemberCog(commands.Cog):
|
||||||
)
|
)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_member_update(
|
async def on_member_update(self, before: discord.Member, after: discord.Member) -> None:
|
||||||
self, before: discord.Member, after: discord.Member
|
"""Process on_member_update events.
|
||||||
):
|
|
||||||
|
Caches events due to double-send bug
|
||||||
|
"""
|
||||||
h = hash(hash(before) * hash(after))
|
h = hash(hash(before) * hash(after))
|
||||||
if h not in self.cache:
|
if h not in self.cache:
|
||||||
self.cache.append(h)
|
self.cache.append(h)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
modlog = Setting.objects(
|
modlog = Setting.objects(guild=before.guild.id, setting="modlog").first()
|
||||||
guild=before.guild.id, setting="modlog"
|
|
||||||
).first()
|
|
||||||
if modlog:
|
if modlog:
|
||||||
channel = after.guild.get_channel(modlog.value)
|
channel = after.guild.get_channel(modlog.value)
|
||||||
await asyncio.sleep(0.5) # Need to wait for audit log
|
await asyncio.sleep(0.5) # Need to wait for audit log
|
||||||
embed = None
|
embed = None
|
||||||
mute = Setting.objects(
|
mute = Setting.objects(guild=before.guild.id, setting="mute").first()
|
||||||
guild=before.guild.id, setting="mute"
|
verified = Setting.objects(guild=before.guild.id, setting="verified").first()
|
||||||
).first()
|
|
||||||
verified = Setting.objects(
|
|
||||||
guild=before.guild.id, setting="verified"
|
|
||||||
).first()
|
|
||||||
mute_role = None
|
mute_role = None
|
||||||
verified_role = None
|
verified_role = None
|
||||||
if mute:
|
if mute:
|
||||||
mute_role = before.guild.get_role(mute.value)
|
mute_role = before.guild.get_role(mute.value)
|
||||||
if verified:
|
if verified:
|
||||||
verified_role = before.guild.get_role(verified.value)
|
verified_role = before.guild.get_role(verified.value)
|
||||||
if (
|
if mute and mute_role in after.roles and mute_role not in before.roles:
|
||||||
mute
|
|
||||||
and mute_role in after.roles
|
|
||||||
and mute_role not in before.roles
|
|
||||||
):
|
|
||||||
embed = await self.process_mute(before, after)
|
embed = await self.process_mute(before, after)
|
||||||
elif (
|
elif mute and mute_role in before.roles and mute_role not in after.roles:
|
||||||
mute
|
|
||||||
and mute_role in before.roles
|
|
||||||
and mute_role not in after.roles
|
|
||||||
):
|
|
||||||
embed = await self.process_unmute(before, after)
|
embed = await self.process_unmute(before, after)
|
||||||
elif (
|
elif verified and verified_role not in before.roles and verified_role in after.roles:
|
||||||
verified
|
|
||||||
and verified_role not in before.roles
|
|
||||||
and verified_role in after.roles
|
|
||||||
):
|
|
||||||
embed = await self.process_verify(before, after)
|
embed = await self.process_verify(before, after)
|
||||||
elif before.nick != after.nick:
|
elif before.nick != after.nick:
|
||||||
auditlog = await before.guild.audit_logs(
|
auditlog = await before.guild.audit_logs(
|
||||||
|
@ -301,21 +301,18 @@ class ModlogMemberCog(commands.Cog):
|
||||||
fields = [
|
fields = [
|
||||||
Field(
|
Field(
|
||||||
name="Before",
|
name="Before",
|
||||||
value=f"{bname} ({before.name}"
|
value=f"{bname} ({before.name}#{before.discriminator})",
|
||||||
+ f"#{before.discriminator})",
|
|
||||||
),
|
),
|
||||||
Field(
|
Field(
|
||||||
name="After",
|
name="After",
|
||||||
value=f"{aname} ({after.name}"
|
value=f"{aname} ({after.name}#{after.discriminator})",
|
||||||
+ f"#{after.discriminator})",
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
if log.user.id != before.id:
|
if log.user.id != before.id:
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name="Moderator",
|
name="Moderator",
|
||||||
value=f"{log.user.mention} ({log.user.name}"
|
value=f"{log.user.mention} ({log.user.name}#{log.user.discriminator})",
|
||||||
+ f"#{log.user.discriminator})",
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if log.reason:
|
if log.reason:
|
||||||
|
@ -333,9 +330,7 @@ class ModlogMemberCog(commands.Cog):
|
||||||
name=f"{after.name}",
|
name=f"{after.name}",
|
||||||
icon_url=after.avatar_url,
|
icon_url=after.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{after.name}#{after.discriminator} | {after.id}")
|
||||||
text=f"{after.name}#{after.discriminator} | {after.id}"
|
|
||||||
)
|
|
||||||
elif len(before.roles) != len(after.roles):
|
elif len(before.roles) != len(after.roles):
|
||||||
# TODO: User got a new role
|
# TODO: User got a new role
|
||||||
embed = await self.process_rolechange(before, after)
|
embed = await self.process_rolechange(before, after)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""J.A.R.V.I.S. ModlogMessageCog."""
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
|
@ -7,17 +8,16 @@ from jarvis.utils.field import Field
|
||||||
|
|
||||||
|
|
||||||
class ModlogMessageCog(commands.Cog):
|
class ModlogMessageCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. ModlogMessageCog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_message_edit(
|
async def on_message_edit(self, before: discord.Message, after: discord.Message) -> None:
|
||||||
self, before: discord.Message, after: discord.Message
|
"""Process on_message_edit events."""
|
||||||
):
|
|
||||||
if not before.author.bot:
|
if not before.author.bot:
|
||||||
modlog = Setting.objects(
|
modlog = Setting.objects(guild=after.guild.id, setting="modlog").first()
|
||||||
guild=after.guild.id, setting="modlog"
|
|
||||||
).first()
|
|
||||||
if modlog:
|
if modlog:
|
||||||
if before.content == after.content or before.content is None:
|
if before.content == after.content or before.content is None:
|
||||||
return
|
return
|
||||||
|
@ -47,26 +47,18 @@ class ModlogMessageCog(commands.Cog):
|
||||||
icon_url=before.author.avatar_url,
|
icon_url=before.author.avatar_url,
|
||||||
url=after.jump_url,
|
url=after.jump_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{before.author.name}#{before.author.discriminator} | {before.author.id}")
|
||||||
text=f"{before.author.name}#{before.author.discriminator}"
|
|
||||||
+ f" | {before.author.id}"
|
|
||||||
)
|
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_message_delete(self, message: discord.Message):
|
async def on_message_delete(self, message: discord.Message) -> None:
|
||||||
modlog = Setting.objects(
|
"""Process on_message_delete events."""
|
||||||
guild=message.guild.id, setting="modlog"
|
modlog = Setting.objects(guild=message.guild.id, setting="modlog").first()
|
||||||
).first()
|
|
||||||
if modlog:
|
if modlog:
|
||||||
fields = [
|
fields = [Field("Original Message", message.content or "N/A", False)]
|
||||||
Field("Original Message", message.content or "N/A", False)
|
|
||||||
]
|
|
||||||
|
|
||||||
if message.attachments:
|
if message.attachments:
|
||||||
value = "\n".join(
|
value = "\n".join([f"[{x.filename}]({x.url})" for x in message.attachments])
|
||||||
[f"[{x.filename}]({x.url})" for x in message.attachments]
|
|
||||||
)
|
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name="Attachments",
|
name="Attachments",
|
||||||
|
@ -76,9 +68,7 @@ class ModlogMessageCog(commands.Cog):
|
||||||
)
|
)
|
||||||
|
|
||||||
if message.stickers:
|
if message.stickers:
|
||||||
value = "\n".join(
|
value = "\n".join([f"[{x.name}]({x.image_url})" for x in message.stickers])
|
||||||
[f"[{x.name}]({x.image_url})" for x in message.stickers]
|
|
||||||
)
|
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name="Stickers",
|
name="Stickers",
|
||||||
|
@ -110,8 +100,5 @@ class ModlogMessageCog(commands.Cog):
|
||||||
icon_url=message.author.avatar_url,
|
icon_url=message.author.avatar_url,
|
||||||
url=message.jump_url,
|
url=message.jump_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{message.author.name}#{message.author.discriminator} | {message.author.id}")
|
||||||
text=f"{message.author.name}#{message.author.discriminator}"
|
|
||||||
+ f" | {message.author.id}"
|
|
||||||
)
|
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. Modlog Cog Utilities."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
from discord import AuditLogEntry
|
||||||
|
from discord import Member
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
|
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
|
@ -14,11 +19,11 @@ def modlog_embed(
|
||||||
title: str,
|
title: str,
|
||||||
desc: str,
|
desc: str,
|
||||||
) -> discord.Embed:
|
) -> discord.Embed:
|
||||||
|
"""Get modlog embed."""
|
||||||
fields = [
|
fields = [
|
||||||
Field(
|
Field(
|
||||||
name="Moderator",
|
name="Moderator",
|
||||||
value=f"{admin.mention} ({admin.name}"
|
value=f"{admin.mention} ({admin.name}#{admin.discriminator})",
|
||||||
+ f"#{admin.discriminator})",
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
if log.reason:
|
if log.reason:
|
||||||
|
@ -34,13 +39,12 @@ def modlog_embed(
|
||||||
name=f"{member.name}",
|
name=f"{member.name}",
|
||||||
icon_url=member.avatar_url,
|
icon_url=member.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{member.name}#{member.discriminator} | {member.id}")
|
||||||
text=f"{member.name}#{member.discriminator} | {member.id}"
|
|
||||||
)
|
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
|
|
||||||
def get_latest_log(auditlog, target):
|
def get_latest_log(auditlog: List[AuditLogEntry], target: Member) -> AuditLogEntry:
|
||||||
|
"""Filter AuditLog to get latest entry."""
|
||||||
before = datetime.utcnow() - timedelta(seconds=10)
|
before = datetime.utcnow() - timedelta(seconds=10)
|
||||||
return find(
|
return find(
|
||||||
lambda x: x.target.id == target.id and x.created_at > before,
|
lambda x: x.target.id == target.id and x.created_at > before,
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
"""J.A.R.V.I.S. Owner Cog."""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from inspect import getsource
|
from inspect import getsource
|
||||||
from time import time
|
from time import time
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import DMChannel, User
|
from discord import DMChannel
|
||||||
|
from discord import User
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
import jarvis
|
import jarvis
|
||||||
|
@ -17,23 +20,20 @@ from jarvis.utils.permissions import user_is_bot_admin
|
||||||
|
|
||||||
class OwnerCog(commands.Cog):
|
class OwnerCog(commands.Cog):
|
||||||
"""
|
"""
|
||||||
J.A.R.V.I.S. management cog
|
J.A.R.V.I.S. management cog.
|
||||||
|
|
||||||
Used by admins to control core J.A.R.V.I.S. systems
|
Used by admins to control core J.A.R.V.I.S. systems
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: commands.Cog):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.admins = Config.objects(key="admins").first()
|
self.admins = Config.objects(key="admins").first()
|
||||||
|
|
||||||
@commands.command(name="load", hidden=True)
|
@commands.command(name="load", hidden=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _load_cog(self, ctx, *, cog: str):
|
async def _load_cog(self, ctx: commands.Context, *, cog: str) -> None:
|
||||||
info = await self.bot.application_info()
|
info = await self.bot.application_info()
|
||||||
if (
|
if ctx.message.author == info.owner or ctx.message.author.id in self.admins.value:
|
||||||
ctx.message.author == info.owner
|
|
||||||
or ctx.message.author.id in self.admins.value
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
if "jarvis.cogs." not in cog:
|
if "jarvis.cogs." not in cog:
|
||||||
cog = "jarvis.cogs." + cog.split(".")[-1]
|
cog = "jarvis.cogs." + cog.split(".")[-1]
|
||||||
|
@ -41,9 +41,7 @@ class OwnerCog(commands.Cog):
|
||||||
except commands.errors.ExtensionAlreadyLoaded:
|
except commands.errors.ExtensionAlreadyLoaded:
|
||||||
await ctx.send(f"Cog `{cog}` already loaded")
|
await ctx.send(f"Cog `{cog}` already loaded")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(
|
await ctx.send(f"Failed to load new cog `{cog}`: {type(e).name} - {e}")
|
||||||
f"Failed to load new cog `{cog}`: {type(e).name} - {e}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await ctx.send(f"Successfully loaded new cog `{cog}`")
|
await ctx.send(f"Successfully loaded new cog `{cog}`")
|
||||||
else:
|
else:
|
||||||
|
@ -51,15 +49,12 @@ class OwnerCog(commands.Cog):
|
||||||
|
|
||||||
@commands.command(name="unload", hidden=True)
|
@commands.command(name="unload", hidden=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _unload_cog(self, ctx, *, cog: str):
|
async def _unload_cog(self, ctx: commands.Context, *, cog: str) -> None:
|
||||||
if cog in ["jarvis.cogs.owner", "owner"]:
|
if cog in ["jarvis.cogs.owner", "owner"]:
|
||||||
await ctx.send("Cannot unload `owner` cog")
|
await ctx.send("Cannot unload `owner` cog")
|
||||||
return
|
return
|
||||||
info = await self.bot.application_info()
|
info = await self.bot.application_info()
|
||||||
if (
|
if ctx.message.author == info.owner or ctx.message.author.id in self.admins.value:
|
||||||
ctx.message.author == info.owner
|
|
||||||
or ctx.message.author.id in self.admins.value
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
if "jarvis.cogs." not in cog:
|
if "jarvis.cogs." not in cog:
|
||||||
cog = "jarvis.cogs." + cog.split(".")[-1]
|
cog = "jarvis.cogs." + cog.split(".")[-1]
|
||||||
|
@ -67,9 +62,7 @@ class OwnerCog(commands.Cog):
|
||||||
except commands.errors.ExtensionNotLoaded:
|
except commands.errors.ExtensionNotLoaded:
|
||||||
await ctx.send(f"Cog `{cog}` not loaded")
|
await ctx.send(f"Cog `{cog}` not loaded")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(
|
await ctx.send(f"Failed to unload cog `{cog}` {type(e).__name__} - {e}")
|
||||||
f"Failed to unload cog `{cog}` {type(e).__name__} - {e}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await ctx.send(f"Successfully unloaded cog `{cog}`")
|
await ctx.send(f"Successfully unloaded cog `{cog}`")
|
||||||
else:
|
else:
|
||||||
|
@ -77,15 +70,12 @@ class OwnerCog(commands.Cog):
|
||||||
|
|
||||||
@commands.command(name="reload", hidden=True)
|
@commands.command(name="reload", hidden=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _cog_reload(self, ctx, *, cog: str):
|
async def _cog_reload(self, ctx: commands.Context, *, cog: str) -> None:
|
||||||
if cog in ["jarvis.cogs.owner", "owner"]:
|
if cog in ["jarvis.cogs.owner", "owner"]:
|
||||||
await ctx.send("Cannot reload `owner` cog")
|
await ctx.send("Cannot reload `owner` cog")
|
||||||
return
|
return
|
||||||
info = await self.bot.application_info()
|
info = await self.bot.application_info()
|
||||||
if (
|
if ctx.message.author == info.owner or ctx.message.author.id in self.admins.value:
|
||||||
ctx.message.author == info.owner
|
|
||||||
or ctx.message.author.id in self.admins.value
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
if "jarvis.cogs." not in cog:
|
if "jarvis.cogs." not in cog:
|
||||||
cog = "jarvis.cogs." + cog.split(".")[-1]
|
cog = "jarvis.cogs." + cog.split(".")[-1]
|
||||||
|
@ -95,9 +85,7 @@ class OwnerCog(commands.Cog):
|
||||||
pass
|
pass
|
||||||
self.bot.unload_extension(cog)
|
self.bot.unload_extension(cog)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(
|
await ctx.send(f"Failed to reload cog `{cog}` {type(e).__name__} - {e}")
|
||||||
f"Failed to reload cog `{cog}` {type(e).__name__} - {e}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await ctx.send(f"Successfully reloaded cog `{cog}`")
|
await ctx.send(f"Successfully reloaded cog `{cog}`")
|
||||||
else:
|
else:
|
||||||
|
@ -105,21 +93,15 @@ class OwnerCog(commands.Cog):
|
||||||
|
|
||||||
@commands.group(name="system", hidden=True, pass_context=True)
|
@commands.group(name="system", hidden=True, pass_context=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _system(self, ctx):
|
async def _system(self, ctx: commands.Context) -> None:
|
||||||
if ctx.invoked_subcommand is None:
|
if ctx.invoked_subcommand is None:
|
||||||
await ctx.send(
|
await ctx.send("Usage: `system <subcommand>`\n" + "Subcommands: `restart`, `update`")
|
||||||
"Usage: `system <subcommand>`\n"
|
|
||||||
+ "Subcommands: `restart`, `update`"
|
|
||||||
)
|
|
||||||
|
|
||||||
@_system.command(name="restart", hidden=True)
|
@_system.command(name="restart", hidden=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _restart(self, ctx):
|
async def _restart(self, ctx: commands.Context) -> None:
|
||||||
info = await self.bot.application_info()
|
info = await self.bot.application_info()
|
||||||
if (
|
if ctx.message.author == info.owner or ctx.message.author.id in self.admins.value:
|
||||||
ctx.message.author == info.owner
|
|
||||||
or ctx.message.author.id in self.admins.value
|
|
||||||
):
|
|
||||||
await ctx.send("Restarting core systems...")
|
await ctx.send("Restarting core systems...")
|
||||||
if isinstance(ctx.channel, discord.channel.DMChannel):
|
if isinstance(ctx.channel, discord.channel.DMChannel):
|
||||||
jarvis.restart_ctx = {
|
jarvis.restart_ctx = {
|
||||||
|
@ -137,12 +119,9 @@ class OwnerCog(commands.Cog):
|
||||||
|
|
||||||
@_system.command(name="update", hidden=True)
|
@_system.command(name="update", hidden=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _update(self, ctx):
|
async def _update(self, ctx: commands.Context) -> None:
|
||||||
info = await self.bot.application_info()
|
info = await self.bot.application_info()
|
||||||
if (
|
if ctx.message.author == info.owner or ctx.message.author.id in self.admins.value:
|
||||||
ctx.message.author == info.owner
|
|
||||||
or ctx.message.author.id in self.admins.value
|
|
||||||
):
|
|
||||||
await ctx.send("Updating core systems...")
|
await ctx.send("Updating core systems...")
|
||||||
status = update()
|
status = update()
|
||||||
if status == 0:
|
if status == 0:
|
||||||
|
@ -161,43 +140,36 @@ class OwnerCog(commands.Cog):
|
||||||
elif status == 1:
|
elif status == 1:
|
||||||
await ctx.send("Core systems already up to date.")
|
await ctx.send("Core systems already up to date.")
|
||||||
elif status == 2:
|
elif status == 2:
|
||||||
await ctx.send(
|
await ctx.send("Core system update available, but core is dirty.")
|
||||||
"Core system update available, but core is dirty."
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await ctx.send("I'm afraid I can't let you do that")
|
await ctx.send("I'm afraid I can't let you do that")
|
||||||
|
|
||||||
@_system.command(name="refresh", hidden=True)
|
@_system.command(name="refresh", hidden=True)
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _refresh(self, ctx):
|
async def _refresh(self, ctx: commands.Context) -> None:
|
||||||
reload_config()
|
reload_config()
|
||||||
await ctx.send("System refreshed")
|
await ctx.send("System refreshed")
|
||||||
|
|
||||||
@commands.group(name="admin", hidden=True, pass_context=True)
|
@commands.group(name="admin", hidden=True, pass_context=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def _admin(self, ctx):
|
async def _admin(self, ctx: commands.Context) -> None:
|
||||||
if ctx.invoked_subcommand is None:
|
if ctx.invoked_subcommand is None:
|
||||||
await ctx.send(
|
await ctx.send("Usage: `admin <subcommand>`\n" + "Subcommands: `add`, `remove`")
|
||||||
"Usage: `admin <subcommand>`\n"
|
|
||||||
+ "Subcommands: `add`, `remove`"
|
|
||||||
)
|
|
||||||
|
|
||||||
@_admin.command(name="add", hidden=True)
|
@_admin.command(name="add", hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def _add(self, ctx, user: User):
|
async def _add(self, ctx: commands.Context, user: User) -> None:
|
||||||
if user.id in self.admins.value:
|
if user.id in self.admins.value:
|
||||||
await ctx.send(f"{user.mention} is already an admin.")
|
await ctx.send(f"{user.mention} is already an admin.")
|
||||||
return
|
return
|
||||||
self.admins.value.append(user.id)
|
self.admins.value.append(user.id)
|
||||||
self.admins.save()
|
self.admins.save()
|
||||||
reload_config()
|
reload_config()
|
||||||
await ctx.send(
|
await ctx.send(f"{user.mention} is now an admin. Use this power carefully.")
|
||||||
f"{user.mention} is now an admin. Use this power carefully."
|
|
||||||
)
|
|
||||||
|
|
||||||
@_admin.command(name="remove", hidden=True)
|
@_admin.command(name="remove", hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def _remove(self, ctx, user: User):
|
async def _remove(self, ctx: commands.Context, user: User) -> None:
|
||||||
if user.id not in self.admins.value:
|
if user.id not in self.admins.value:
|
||||||
await ctx.send(f"{user.mention} is not an admin.")
|
await ctx.send(f"{user.mention} is not an admin.")
|
||||||
return
|
return
|
||||||
|
@ -206,14 +178,12 @@ class OwnerCog(commands.Cog):
|
||||||
reload_config()
|
reload_config()
|
||||||
await ctx.send(f"{user.mention} is no longer an admin.")
|
await ctx.send(f"{user.mention} is no longer an admin.")
|
||||||
|
|
||||||
def resolve_variable(self, variable):
|
def resolve_variable(self, variable: Any) -> Any:
|
||||||
|
"""Resolve a variable from eval."""
|
||||||
if hasattr(variable, "__iter__"):
|
if hasattr(variable, "__iter__"):
|
||||||
var_length = len(list(variable))
|
var_length = len(list(variable))
|
||||||
if (var_length > 100) and (not isinstance(variable, str)):
|
if (var_length > 100) and (not isinstance(variable, str)):
|
||||||
return (
|
return f"<a {type(variable).__name__} iterable " + f"with more than 100 values ({var_length})>"
|
||||||
f"<a {type(variable).__name__} iterable "
|
|
||||||
+ f"with more than 100 values ({var_length})>"
|
|
||||||
)
|
|
||||||
elif not var_length:
|
elif not var_length:
|
||||||
return f"<an empty {type(variable).__name__} iterable>"
|
return f"<an empty {type(variable).__name__} iterable>"
|
||||||
|
|
||||||
|
@ -222,24 +192,19 @@ class OwnerCog(commands.Cog):
|
||||||
return (
|
return (
|
||||||
variable
|
variable
|
||||||
if (len(f"{variable}") <= 1000)
|
if (len(f"{variable}") <= 1000)
|
||||||
else f"<a long {type(variable).__name__} object "
|
else f"<a long {type(variable).__name__} object " + f"with the length of {len(f'{variable}'):,}>"
|
||||||
+ f"with the length of {len(f'{variable}'):,}>"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def prepare(self, string):
|
def prepare(self, string: str) -> str:
|
||||||
arr = (
|
"""Prepare string for eval."""
|
||||||
string.strip("```")
|
arr = string.strip("```").replace("py\n", "").replace("python\n", "").split("\n")
|
||||||
.replace("py\n", "")
|
|
||||||
.replace("python\n", "")
|
|
||||||
.split("\n")
|
|
||||||
)
|
|
||||||
if not arr[::-1][0].replace(" ", "").startswith("return"):
|
if not arr[::-1][0].replace(" ", "").startswith("return"):
|
||||||
arr[len(arr) - 1] = "return " + arr[::-1][0]
|
arr[len(arr) - 1] = "return " + arr[::-1][0]
|
||||||
return "".join(f"\n\t{i}" for i in arr)
|
return "".join(f"\n\t{i}" for i in arr)
|
||||||
|
|
||||||
@commands.command(pass_context=True, aliases=["eval", "exec", "evaluate"])
|
@commands.command(pass_context=True, aliases=["eval", "exec", "evaluate"])
|
||||||
@user_is_bot_admin()
|
@user_is_bot_admin()
|
||||||
async def _eval(self, ctx, *, code: str):
|
async def _eval(self, ctx: commands.Context, *, code: str) -> None:
|
||||||
if not isinstance(ctx.message.channel, DMChannel):
|
if not isinstance(ctx.message.channel, DMChannel):
|
||||||
return
|
return
|
||||||
code = self.prepare(code)
|
code = self.prepare(code)
|
||||||
|
@ -254,13 +219,13 @@ class OwnerCog(commands.Cog):
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exec(
|
exec( # noqa: S102
|
||||||
f"async def func():{code}",
|
f"async def func():{code}",
|
||||||
globals().update(args),
|
globals().update(args),
|
||||||
locals(),
|
locals(),
|
||||||
)
|
)
|
||||||
a = time()
|
a = time()
|
||||||
response = await eval("func()", globals().update(args), locals())
|
response = await eval("func()", globals().update(args), locals()) # noqa: S307
|
||||||
if response is None or isinstance(response, discord.Message):
|
if response is None or isinstance(response, discord.Message):
|
||||||
del args, code
|
del args, code
|
||||||
return
|
return
|
||||||
|
@ -269,8 +234,7 @@ class OwnerCog(commands.Cog):
|
||||||
response = response.replace("`", "")
|
response = response.replace("`", "")
|
||||||
|
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"```py\n{self.resolve_variable(response)}```"
|
f"```py\n{self.resolve_variable(response)}```\n`{type(response).__name__} | {(time() - a) / 1000} ms`"
|
||||||
+ f"`{type(response).__name__} | {(time() - a) / 1000} ms`"
|
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
await ctx.send(f"Error occurred:```\n{traceback.format_exc()}```")
|
await ctx.send(f"Error occurred:```\n{traceback.format_exc()}```")
|
||||||
|
@ -278,5 +242,6 @@ class OwnerCog(commands.Cog):
|
||||||
del args, code
|
del args, code
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add OwnerCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(OwnerCog(bot))
|
bot.add_cog(OwnerCog(bot))
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
|
"""J.A.R.V.I.S. Remind Me Cog."""
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
from discord.ext import commands
|
from discord import Embed
|
||||||
|
from discord.ext.commands import Bot
|
||||||
from discord.ext.tasks import loop
|
from discord.ext.tasks import loop
|
||||||
from discord.utils import find
|
from discord_slash import cog_ext
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
from discord_slash.utils.manage_components import (
|
from discord_slash.utils.manage_components import create_actionrow
|
||||||
create_actionrow,
|
from discord_slash.utils.manage_components import create_select
|
||||||
create_select,
|
from discord_slash.utils.manage_components import create_select_option
|
||||||
create_select_option,
|
from discord_slash.utils.manage_components import wait_for_component
|
||||||
wait_for_component,
|
|
||||||
)
|
|
||||||
|
|
||||||
from jarvis.db.models import Reminder
|
from jarvis.db.models import Reminder
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
|
@ -29,7 +31,9 @@ invites = re.compile(
|
||||||
|
|
||||||
|
|
||||||
class RemindmeCog(CacheCog):
|
class RemindmeCog(CacheCog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Remind Me Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
super().__init__(bot)
|
super().__init__(bot)
|
||||||
self._remind.start()
|
self._remind.start()
|
||||||
|
|
||||||
|
@ -77,7 +81,7 @@ class RemindmeCog(CacheCog):
|
||||||
days: Optional[int] = 0,
|
days: Optional[int] = 0,
|
||||||
hours: Optional[int] = 0,
|
hours: Optional[int] = 0,
|
||||||
minutes: Optional[int] = 0,
|
minutes: Optional[int] = 0,
|
||||||
):
|
) -> None:
|
||||||
if len(message) > 100:
|
if len(message) > 100:
|
||||||
await ctx.send("Reminder cannot be > 100 characters.", hidden=True)
|
await ctx.send("Reminder cannot be > 100 characters.", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -88,9 +92,7 @@ class RemindmeCog(CacheCog):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
elif not valid.fullmatch(message):
|
elif not valid.fullmatch(message):
|
||||||
await ctx.send(
|
await ctx.send("Hey, you should probably make this readable", hidden=True)
|
||||||
"Hey, you should probably make this readable", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if not any([weeks, days, hours, minutes]):
|
if not any([weeks, days, hours, minutes]):
|
||||||
|
@ -107,28 +109,22 @@ class RemindmeCog(CacheCog):
|
||||||
return
|
return
|
||||||
|
|
||||||
elif days and days > 6:
|
elif days and days > 6:
|
||||||
await ctx.send(
|
await ctx.send("Use weeks instead of 7+ days, please.", hidden=True)
|
||||||
"Use weeks instead of 7+ days, please.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
elif hours and hours > 23:
|
elif hours and hours > 23:
|
||||||
await ctx.send(
|
await ctx.send("Use days instead of 24+ hours, please.", hidden=True)
|
||||||
"Use days instead of 24+ hours, please.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
elif minutes and minutes > 59:
|
elif minutes and minutes > 59:
|
||||||
await ctx.send(
|
await ctx.send("Use hours instead of 59+ minutes, please.", hidden=True)
|
||||||
"Use hours instead of 59+ minutes, please.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
reminders = Reminder.objects(user=ctx.author.id, active=True).count()
|
reminders = Reminder.objects(user=ctx.author.id, active=True).count()
|
||||||
if reminders >= 5:
|
if reminders >= 5:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"You already have 5 (or more) active reminders. "
|
"You already have 5 (or more) active reminders. "
|
||||||
+ "Please either remove an old one, or wait for one to pass",
|
"Please either remove an old one, or wait for one to pass",
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -170,7 +166,8 @@ class RemindmeCog(CacheCog):
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
async def get_reminders_embed(self, ctx, reminders):
|
async def get_reminders_embed(self, ctx: SlashContext, reminders: List[Reminder]) -> Embed:
|
||||||
|
"""Build embed for paginator."""
|
||||||
fields = []
|
fields = []
|
||||||
for reminder in reminders:
|
for reminder in reminders:
|
||||||
fields.append(
|
fields.append(
|
||||||
|
@ -183,7 +180,7 @@ class RemindmeCog(CacheCog):
|
||||||
|
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
title=f"{len(reminders)} Active Reminder(s)",
|
title=f"{len(reminders)} Active Reminder(s)",
|
||||||
description="All active reminders for " + f"{ctx.author.mention}",
|
description=f"All active reminders for {ctx.author.mention}",
|
||||||
fields=fields,
|
fields=fields,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -200,13 +197,12 @@ class RemindmeCog(CacheCog):
|
||||||
name="list",
|
name="list",
|
||||||
description="List reminders for a user",
|
description="List reminders for a user",
|
||||||
)
|
)
|
||||||
async def _list(self, ctx: SlashContext):
|
async def _list(self, ctx: SlashContext) -> None:
|
||||||
exists = self.check_cache(ctx)
|
exists = self.check_cache(ctx)
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.defer(hidden=True)
|
await ctx.defer(hidden=True)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Please use existing interaction: "
|
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
|
||||||
+ f"{exists['paginator']._message.jump_url}",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -224,7 +220,7 @@ class RemindmeCog(CacheCog):
|
||||||
name="delete",
|
name="delete",
|
||||||
description="Delete a reminder",
|
description="Delete a reminder",
|
||||||
)
|
)
|
||||||
async def _delete(self, ctx: SlashContext):
|
async def _delete(self, ctx: SlashContext) -> None:
|
||||||
reminders = Reminder.objects(user=ctx.author.id, active=True)
|
reminders = Reminder.objects(user=ctx.author.id, active=True)
|
||||||
if not reminders:
|
if not reminders:
|
||||||
await ctx.send("You have no reminders set", hidden=True)
|
await ctx.send("You have no reminders set", hidden=True)
|
||||||
|
@ -263,18 +259,14 @@ class RemindmeCog(CacheCog):
|
||||||
timeout=60 * 5,
|
timeout=60 * 5,
|
||||||
)
|
)
|
||||||
for to_delete in context.selected_options:
|
for to_delete in context.selected_options:
|
||||||
_ = Reminder.objects(
|
_ = Reminder.objects(user=ctx.author.id, id=ObjectId(to_delete)).delete()
|
||||||
user=ctx.author.id, id=ObjectId(to_delete)
|
|
||||||
).delete()
|
|
||||||
|
|
||||||
for row in components:
|
for row in components:
|
||||||
for component in row["components"]:
|
for component in row["components"]:
|
||||||
component["disabled"] = True
|
component["disabled"] = True
|
||||||
|
|
||||||
fields = []
|
fields = []
|
||||||
for reminder in filter(
|
for reminder in filter(lambda x: str(x._id) in context.selected_options, reminders):
|
||||||
lambda x: str(x._id) in context.selected_options, reminders
|
|
||||||
):
|
|
||||||
fields.append(
|
fields.append(
|
||||||
Field(
|
Field(
|
||||||
name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"),
|
name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"),
|
||||||
|
@ -306,10 +298,8 @@ class RemindmeCog(CacheCog):
|
||||||
await message.edit(components=components)
|
await message.edit(components=components)
|
||||||
|
|
||||||
@loop(seconds=15)
|
@loop(seconds=15)
|
||||||
async def _remind(self):
|
async def _remind(self) -> None:
|
||||||
reminders = Reminder.objects(
|
reminders = Reminder.objects(remind_at__lte=datetime.utcnow() + timedelta(seconds=30))
|
||||||
remind_at__lte=datetime.utcnow() + timedelta(seconds=30)
|
|
||||||
)
|
|
||||||
for reminder in reminders:
|
for reminder in reminders:
|
||||||
if reminder.remind_at <= datetime.utcnow():
|
if reminder.remind_at <= datetime.utcnow():
|
||||||
user = await self.bot.fetch_user(reminder.user)
|
user = await self.bot.fetch_user(reminder.user)
|
||||||
|
@ -328,16 +318,15 @@ class RemindmeCog(CacheCog):
|
||||||
embed.set_thumbnail(url=user.avatar_url)
|
embed.set_thumbnail(url=user.avatar_url)
|
||||||
try:
|
try:
|
||||||
await user.send(embed=embed)
|
await user.send(embed=embed)
|
||||||
except:
|
except Exception:
|
||||||
guild = self.bot.fetch_guild(reminder.guild)
|
guild = self.bot.fetch_guild(reminder.guild)
|
||||||
channel = (
|
channel = guild.get_channel(reminder.channel) if guild else None
|
||||||
guild.get_channel(reminder.channel) if guild else None
|
|
||||||
)
|
|
||||||
if channel:
|
if channel:
|
||||||
await channel.send(f"{user.mention}", embed=embed)
|
await channel.send(f"{user.mention}", embed=embed)
|
||||||
finally:
|
finally:
|
||||||
reminder.delete()
|
reminder.delete()
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: Bot) -> None:
|
||||||
|
"""Add RemindmeCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(RemindmeCog(bot))
|
bot.add_cog(RemindmeCog(bot))
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
"""J.A.R.V.I.S. Role Giver Cog."""
|
||||||
from discord import Role
|
from discord import Role
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Setting
|
from jarvis.db.models import Setting
|
||||||
|
@ -10,7 +12,9 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class RolegiverCog(commands.Cog):
|
class RolegiverCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Role Giver Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -27,18 +31,14 @@ class RolegiverCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _rolegiver_add(self, ctx: SlashContext, role: Role):
|
async def _rolegiver_add(self, ctx: SlashContext, role: Role) -> None:
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="rolegiver").first()
|
||||||
guild=ctx.guild.id, setting="rolegiver"
|
|
||||||
).first()
|
|
||||||
if setting and role.id in setting.value:
|
if setting and role.id in setting.value:
|
||||||
await ctx.send("Role already in rolegiver", hidden=True)
|
await ctx.send("Role already in rolegiver", hidden=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not setting:
|
if not setting:
|
||||||
setting = Setting(
|
setting = Setting(guild=ctx.guild.id, setting="rolegiver", value=[])
|
||||||
guild=ctx.guild.id, setting="rolegiver", value=[]
|
|
||||||
)
|
|
||||||
|
|
||||||
roles = []
|
roles = []
|
||||||
for role_id in setting.value:
|
for role_id in setting.value:
|
||||||
|
@ -67,10 +67,7 @@ class RolegiverCog(commands.Cog):
|
||||||
icon_url=ctx.author.avatar_url,
|
icon_url=ctx.author.avatar_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{ctx.author.name}#{ctx.author.discriminator} | {ctx.author.id}")
|
||||||
text=f"{ctx.author.name}#{ctx.author.discriminator} "
|
|
||||||
+ f"| {ctx.author.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@ -88,10 +85,8 @@ class RolegiverCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _rolegiver_remove(self, ctx: SlashContext, role: Role):
|
async def _rolegiver_remove(self, ctx: SlashContext, role: Role) -> None:
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="rolegiver").first()
|
||||||
guild=ctx.guild.id, setting="rolegiver"
|
|
||||||
).first()
|
|
||||||
if not setting or (setting and not setting.value):
|
if not setting or (setting and not setting.value):
|
||||||
await ctx.send("Rolegiver has no roles", hidden=True)
|
await ctx.send("Rolegiver has no roles", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -128,10 +123,7 @@ class RolegiverCog(commands.Cog):
|
||||||
icon_url=ctx.author.avatar_url,
|
icon_url=ctx.author.avatar_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{ctx.author.name}#{ctx.author.discriminator} | {ctx.author.id}")
|
||||||
text=f"{ctx.author.name}#{ctx.author.discriminator} "
|
|
||||||
+ f"| {ctx.author.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@ -140,10 +132,8 @@ class RolegiverCog(commands.Cog):
|
||||||
name="list",
|
name="list",
|
||||||
description="List roles rolegiver",
|
description="List roles rolegiver",
|
||||||
)
|
)
|
||||||
async def _rolegiver_list(self, ctx: SlashContext):
|
async def _rolegiver_list(self, ctx: SlashContext) -> None:
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="rolegiver").first()
|
||||||
guild=ctx.guild.id, setting="rolegiver"
|
|
||||||
).first()
|
|
||||||
if not setting or (setting and not setting.value):
|
if not setting or (setting and not setting.value):
|
||||||
await ctx.send("Rolegiver has no roles", hidden=True)
|
await ctx.send("Rolegiver has no roles", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -170,10 +160,7 @@ class RolegiverCog(commands.Cog):
|
||||||
icon_url=ctx.author.avatar_url,
|
icon_url=ctx.author.avatar_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{ctx.author.name}#{ctx.author.discriminator} | {ctx.author.id}")
|
||||||
text=f"{ctx.author.name}#{ctx.author.discriminator} "
|
|
||||||
+ f"| {ctx.author.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@ -191,10 +178,8 @@ class RolegiverCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 10, commands.BucketType.user)
|
@commands.cooldown(1, 10, commands.BucketType.user)
|
||||||
async def _role_get(self, ctx: SlashContext, role: Role):
|
async def _role_get(self, ctx: SlashContext, role: Role) -> None:
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="rolegiver").first()
|
||||||
guild=ctx.guild.id, setting="rolegiver"
|
|
||||||
).first()
|
|
||||||
if not setting or (setting and not setting.value):
|
if not setting or (setting and not setting.value):
|
||||||
await ctx.send("Rolegiver has no roles", hidden=True)
|
await ctx.send("Rolegiver has no roles", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -230,10 +215,7 @@ class RolegiverCog(commands.Cog):
|
||||||
icon_url=ctx.author.avatar_url,
|
icon_url=ctx.author.avatar_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{ctx.author.name}#{ctx.author.discriminator} | {ctx.author.id}")
|
||||||
text=f"{ctx.author.name}#{ctx.author.discriminator} "
|
|
||||||
+ f"| {ctx.author.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@ -251,10 +233,8 @@ class RolegiverCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 10, commands.BucketType.user)
|
@commands.cooldown(1, 10, commands.BucketType.user)
|
||||||
async def _role_forfeit(self, ctx: SlashContext, role: Role):
|
async def _role_forfeit(self, ctx: SlashContext, role: Role) -> None:
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="rolegiver").first()
|
||||||
guild=ctx.guild.id, setting="rolegiver"
|
|
||||||
).first()
|
|
||||||
if not setting or (setting and not setting.value):
|
if not setting or (setting and not setting.value):
|
||||||
await ctx.send("Rolegiver has no roles", hidden=True)
|
await ctx.send("Rolegiver has no roles", hidden=True)
|
||||||
return
|
return
|
||||||
|
@ -290,13 +270,11 @@ class RolegiverCog(commands.Cog):
|
||||||
icon_url=ctx.author.avatar_url,
|
icon_url=ctx.author.avatar_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{ctx.author.name}#{ctx.author.discriminator} | {ctx.author.id}")
|
||||||
text=f"{ctx.author.name}#{ctx.author.discriminator} "
|
|
||||||
+ f"| {ctx.author.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add RolegiverCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(RolegiverCog(bot))
|
bot.add_cog(RolegiverCog(bot))
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
from discord import Role, TextChannel
|
"""J.A.R.V.I.S. Settings Management Cog."""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from discord import Role
|
||||||
|
from discord import TextChannel
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
|
||||||
from jarvis.db.models import Setting
|
from jarvis.db.models import Setting
|
||||||
|
@ -11,10 +16,13 @@ from jarvis.utils.permissions import admin_or_permissions
|
||||||
|
|
||||||
|
|
||||||
class SettingsCog(commands.Cog):
|
class SettingsCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Settings Management Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
def update_settings(self, setting, value, guild):
|
def update_settings(self, setting: str, value: Any, guild: int) -> bool:
|
||||||
|
"""Update a guild setting."""
|
||||||
setting = Setting.objects(setting=setting, guild=guild).first()
|
setting = Setting.objects(setting=setting, guild=guild).first()
|
||||||
if not setting:
|
if not setting:
|
||||||
setting = Setting(setting=setting, guild=guild, value=value)
|
setting = Setting(setting=setting, guild=guild, value=value)
|
||||||
|
@ -22,7 +30,8 @@ class SettingsCog(commands.Cog):
|
||||||
|
|
||||||
return updated is not None
|
return updated is not None
|
||||||
|
|
||||||
def delete_settings(self, setting, guild):
|
def delete_settings(self, setting: str, guild: int) -> bool:
|
||||||
|
"""Delete a guild setting."""
|
||||||
return Setting.objects(setting=setting, guild=guild).delete()
|
return Setting.objects(setting=setting, guild=guild).delete()
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -42,7 +51,7 @@ class SettingsCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _set_mute(self, ctx, role: Role):
|
async def _set_mute(self, ctx: SlashContext, role: Role) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.update_settings("mute", role.id, ctx.guild.id)
|
self.update_settings("mute", role.id, ctx.guild.id)
|
||||||
await ctx.send(f"Settings applied. New mute role is `{role.name}`")
|
await ctx.send(f"Settings applied. New mute role is `{role.name}`")
|
||||||
|
@ -62,14 +71,12 @@ class SettingsCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _set_modlog(self, ctx, channel: TextChannel):
|
async def _set_modlog(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
if not isinstance(channel, TextChannel):
|
if not isinstance(channel, TextChannel):
|
||||||
await ctx.send("Channel must be a TextChannel", hidden=True)
|
await ctx.send("Channel must be a TextChannel", hidden=True)
|
||||||
return
|
return
|
||||||
self.update_settings("modlog", channel.id, ctx.guild.id)
|
self.update_settings("modlog", channel.id, ctx.guild.id)
|
||||||
await ctx.send(
|
await ctx.send(f"Settings applied. New modlog channel is {channel.mention}")
|
||||||
f"Settings applied. New modlog channel is {channel.mention}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="settings",
|
base="settings",
|
||||||
|
@ -86,14 +93,12 @@ class SettingsCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _set_userlog(self, ctx, channel: TextChannel):
|
async def _set_userlog(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
if not isinstance(channel, TextChannel):
|
if not isinstance(channel, TextChannel):
|
||||||
await ctx.send("Channel must be a TextChannel", hidden=True)
|
await ctx.send("Channel must be a TextChannel", hidden=True)
|
||||||
return
|
return
|
||||||
self.update_settings("userlog", channel.id, ctx.guild.id)
|
self.update_settings("userlog", channel.id, ctx.guild.id)
|
||||||
await ctx.send(
|
await ctx.send(f"Settings applied. New userlog channel is {channel.mention}")
|
||||||
f"Settings applied. New userlog channel is {channel.mention}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="settings",
|
base="settings",
|
||||||
|
@ -110,7 +115,7 @@ class SettingsCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _set_massmention(self, ctx, amount: int):
|
async def _set_massmention(self, ctx: SlashContext, amount: int) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.update_settings("massmention", amount, ctx.guild.id)
|
self.update_settings("massmention", amount, ctx.guild.id)
|
||||||
await ctx.send(f"Settings applied. New massmention limit is {amount}")
|
await ctx.send(f"Settings applied. New massmention limit is {amount}")
|
||||||
|
@ -130,7 +135,7 @@ class SettingsCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _set_verified(self, ctx, role: Role):
|
async def _set_verified(self, ctx: SlashContext, role: Role) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.update_settings("verified", role.id, ctx.guild.id)
|
self.update_settings("verified", role.id, ctx.guild.id)
|
||||||
await ctx.send(f"Settings applied. New verified role is `{role.name}`")
|
await ctx.send(f"Settings applied. New verified role is `{role.name}`")
|
||||||
|
@ -150,12 +155,10 @@ class SettingsCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _set_unverified(self, ctx, role: Role):
|
async def _set_unverified(self, ctx: SlashContext, role: Role) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.update_settings("unverified", role.id, ctx.guild.id)
|
self.update_settings("unverified", role.id, ctx.guild.id)
|
||||||
await ctx.send(
|
await ctx.send(f"Settings applied. New unverified role is `{role.name}`")
|
||||||
f"Settings applied. New unverified role is `{role.name}`"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="settings",
|
base="settings",
|
||||||
|
@ -165,7 +168,7 @@ class SettingsCog(commands.Cog):
|
||||||
description="Unset mute role",
|
description="Unset mute role",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _unset_mute(self, ctx):
|
async def _unset_mute(self, ctx: SlashContext) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.delete_settings("mute", ctx.guild.id)
|
self.delete_settings("mute", ctx.guild.id)
|
||||||
await ctx.send("Setting removed.")
|
await ctx.send("Setting removed.")
|
||||||
|
@ -177,7 +180,7 @@ class SettingsCog(commands.Cog):
|
||||||
description="Unset modlog channel",
|
description="Unset modlog channel",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _unset_modlog(self, ctx):
|
async def _unset_modlog(self, ctx: SlashContext) -> None:
|
||||||
self.delete_settings("modlog", ctx.guild.id)
|
self.delete_settings("modlog", ctx.guild.id)
|
||||||
await ctx.send("Setting removed.")
|
await ctx.send("Setting removed.")
|
||||||
|
|
||||||
|
@ -188,7 +191,7 @@ class SettingsCog(commands.Cog):
|
||||||
description="Unset userlog channel",
|
description="Unset userlog channel",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _unset_userlog(self, ctx):
|
async def _unset_userlog(self, ctx: SlashContext) -> None:
|
||||||
self.delete_settings("userlog", ctx.guild.id)
|
self.delete_settings("userlog", ctx.guild.id)
|
||||||
await ctx.send("Setting removed.")
|
await ctx.send("Setting removed.")
|
||||||
|
|
||||||
|
@ -199,7 +202,7 @@ class SettingsCog(commands.Cog):
|
||||||
description="Unet massmention amount",
|
description="Unet massmention amount",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _massmention(self, ctx):
|
async def _massmention(self, ctx: SlashContext) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.delete_settings("massmention", ctx.guild.id)
|
self.delete_settings("massmention", ctx.guild.id)
|
||||||
await ctx.send("Setting removed.")
|
await ctx.send("Setting removed.")
|
||||||
|
@ -211,7 +214,7 @@ class SettingsCog(commands.Cog):
|
||||||
description="Unset verified role",
|
description="Unset verified role",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _verified(self, ctx):
|
async def _verified(self, ctx: SlashContext) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.delete_settings("verified", ctx.guild.id)
|
self.delete_settings("verified", ctx.guild.id)
|
||||||
await ctx.send("Setting removed.")
|
await ctx.send("Setting removed.")
|
||||||
|
@ -223,16 +226,14 @@ class SettingsCog(commands.Cog):
|
||||||
description="Unset unverified role",
|
description="Unset unverified role",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _unverified(self, ctx):
|
async def _unverified(self, ctx: SlashContext) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
self.delete_settings("unverified", ctx.guild.id)
|
self.delete_settings("unverified", ctx.guild.id)
|
||||||
await ctx.send("Setting removed.")
|
await ctx.send("Setting removed.")
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(base="settings", name="view", description="View settings")
|
||||||
base="settings", name="view", description="View settings"
|
|
||||||
)
|
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _view(self, ctx: SlashContext):
|
async def _view(self, ctx: SlashContext) -> None:
|
||||||
settings = Setting.objects(guild=ctx.guild.id)
|
settings = Setting.objects(guild=ctx.guild.id)
|
||||||
|
|
||||||
fields = []
|
fields = []
|
||||||
|
@ -260,20 +261,17 @@ class SettingsCog(commands.Cog):
|
||||||
value += "\n||`[redacted]`||"
|
value += "\n||`[redacted]`||"
|
||||||
fields.append(Field(name=setting.setting, value=value or "N/A"))
|
fields.append(Field(name=setting.setting, value=value or "N/A"))
|
||||||
|
|
||||||
embed = build_embed(
|
embed = build_embed(title="Current Settings", description="", fields=fields)
|
||||||
title="Current Settings", description="", fields=fields
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(base="settings", name="clear", description="Clear all settings")
|
||||||
base="settings", name="clear", description="Clear all settings"
|
|
||||||
)
|
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _clear(self, ctx: SlashContext):
|
async def _clear(self, ctx: SlashContext) -> None:
|
||||||
deleted = Setting.objects(guild=ctx.guild.id).delete()
|
deleted = Setting.objects(guild=ctx.guild.id).delete()
|
||||||
await ctx.send(f"Guild settings cleared: `{deleted is not None}`")
|
await ctx.send(f"Guild settings cleared: `{deleted is not None}`")
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add SettingsCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(SettingsCog(bot))
|
bot.add_cog(SettingsCog(bot))
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
|
"""J.A.R.V.I.S. Starboard Cog."""
|
||||||
from discord import TextChannel
|
from discord import TextChannel
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.utils.manage_commands import create_option
|
from discord_slash.utils.manage_commands import create_option
|
||||||
from discord_slash.utils.manage_components import (
|
from discord_slash.utils.manage_components import create_actionrow
|
||||||
create_actionrow,
|
from discord_slash.utils.manage_components import create_select
|
||||||
create_select,
|
from discord_slash.utils.manage_components import create_select_option
|
||||||
create_select_option,
|
from discord_slash.utils.manage_components import wait_for_component
|
||||||
wait_for_component,
|
|
||||||
)
|
|
||||||
|
|
||||||
from jarvis.db.models import Star, Starboard
|
from jarvis.db.models import Star
|
||||||
|
from jarvis.db.models import 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
|
||||||
|
|
||||||
|
@ -24,7 +25,9 @@ supported_images = [
|
||||||
|
|
||||||
|
|
||||||
class StarboardCog(commands.Cog):
|
class StarboardCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Starboard Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
|
@ -33,7 +36,7 @@ class StarboardCog(commands.Cog):
|
||||||
description="Lists all Starboards",
|
description="Lists all Starboards",
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _list(self, ctx):
|
async def _list(self, ctx: SlashContext) -> None:
|
||||||
starboards = Starboard.objects(guild=ctx.guild.id)
|
starboards = Starboard.objects(guild=ctx.guild.id)
|
||||||
if starboards != []:
|
if starboards != []:
|
||||||
message = "Available Starboards:\n"
|
message = "Available Starboards:\n"
|
||||||
|
@ -57,7 +60,7 @@ class StarboardCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _create(self, ctx, channel: TextChannel):
|
async def _create(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
if channel not in ctx.guild.channels:
|
if channel not in ctx.guild.channels:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Channel not in guild. Choose an existing channel.",
|
"Channel not in guild. Choose an existing channel.",
|
||||||
|
@ -68,13 +71,9 @@ class StarboardCog(commands.Cog):
|
||||||
await ctx.send("Channel must be a TextChannel", hidden=True)
|
await ctx.send("Channel must be a TextChannel", hidden=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
exists = Starboard.objects(
|
exists = Starboard.objects(channel=channel.id, guild=ctx.guild.id).first()
|
||||||
channel=channel.id, guild=ctx.guild.id
|
|
||||||
).first()
|
|
||||||
if exists:
|
if exists:
|
||||||
await ctx.send(
|
await ctx.send(f"Starboard already exists at {channel.mention}.", hidden=True)
|
||||||
f"Starboard already exists at {channel.mention}.", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
count = Starboard.objects(guild=ctx.guild.id).count()
|
count = Starboard.objects(guild=ctx.guild.id).count()
|
||||||
|
@ -87,9 +86,7 @@ class StarboardCog(commands.Cog):
|
||||||
channel=channel.id,
|
channel=channel.id,
|
||||||
admin=ctx.author.id,
|
admin=ctx.author.id,
|
||||||
).save()
|
).save()
|
||||||
await ctx.send(
|
await ctx.send(f"Starboard created. Check it out at {channel.mention}.")
|
||||||
f"Starboard created. Check it out at {channel.mention}."
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="starboard",
|
base="starboard",
|
||||||
|
@ -105,19 +102,13 @@ class StarboardCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@admin_or_permissions(manage_guild=True)
|
@admin_or_permissions(manage_guild=True)
|
||||||
async def _delete(self, ctx, channel: TextChannel):
|
async def _delete(self, ctx: SlashContext, channel: TextChannel) -> None:
|
||||||
deleted = Starboard.objects(
|
deleted = Starboard.objects(channel=channel.id, guild=ctx.guild.id).delete()
|
||||||
channel=channel.id, guild=ctx.guild.id
|
|
||||||
).delete()
|
|
||||||
if deleted:
|
if deleted:
|
||||||
_ = Star.objects(starboard=channel.id).delete()
|
_ = Star.objects(starboard=channel.id).delete()
|
||||||
await ctx.send(
|
await ctx.send(f"Starboard deleted from {channel.mention}.", hidden=True)
|
||||||
f"Starboard deleted from {channel.mention}.", hidden=True
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await ctx.send(
|
await ctx.send(f"Starboard not found in {channel.mention}.", hidden=True)
|
||||||
f"Starboard not found in {channel.mention}.", hidden=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@cog_ext.cog_subcommand(
|
@cog_ext.cog_subcommand(
|
||||||
base="star",
|
base="star",
|
||||||
|
@ -132,8 +123,7 @@ class StarboardCog(commands.Cog):
|
||||||
),
|
),
|
||||||
create_option(
|
create_option(
|
||||||
name="channel",
|
name="channel",
|
||||||
description="Channel that has the message, "
|
description="Channel that has the message, required if different than command message",
|
||||||
+ "required if different than command message",
|
|
||||||
option_type=7,
|
option_type=7,
|
||||||
required=False,
|
required=False,
|
||||||
),
|
),
|
||||||
|
@ -145,7 +135,7 @@ class StarboardCog(commands.Cog):
|
||||||
ctx: SlashContext,
|
ctx: SlashContext,
|
||||||
message: str,
|
message: str,
|
||||||
channel: TextChannel = None,
|
channel: TextChannel = None,
|
||||||
):
|
) -> None:
|
||||||
if not channel:
|
if not channel:
|
||||||
channel = ctx.channel
|
channel = ctx.channel
|
||||||
starboards = Starboard.objects(guild=ctx.guild.id)
|
starboards = Starboard.objects(guild=ctx.guild.id)
|
||||||
|
@ -156,14 +146,9 @@ class StarboardCog(commands.Cog):
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
channel_list = []
|
channel_list = []
|
||||||
for starboard in starboards:
|
for starboard in starboards:
|
||||||
channel_list.append(
|
channel_list.append(find(lambda x: x.id == starboard.channel, ctx.guild.channels))
|
||||||
find(lambda x: x.id == starboard.channel, ctx.guild.channels)
|
|
||||||
)
|
|
||||||
|
|
||||||
select_channels = [
|
select_channels = [create_select_option(label=x.name, value=str(idx)) for idx, x in enumerate(channel_list)]
|
||||||
create_select_option(label=x.name, value=str(idx))
|
|
||||||
for idx, x in enumerate(channel_list)
|
|
||||||
]
|
|
||||||
|
|
||||||
select = create_select(
|
select = create_select(
|
||||||
options=select_channels,
|
options=select_channels,
|
||||||
|
@ -173,9 +158,7 @@ class StarboardCog(commands.Cog):
|
||||||
|
|
||||||
components = [create_actionrow(select)]
|
components = [create_actionrow(select)]
|
||||||
|
|
||||||
msg = await ctx.send(
|
msg = await ctx.send(content="Choose a starboard", components=components)
|
||||||
content="Choose a starboard", components=components
|
|
||||||
)
|
|
||||||
|
|
||||||
com_ctx = await wait_for_component(
|
com_ctx = await wait_for_component(
|
||||||
self.bot,
|
self.bot,
|
||||||
|
@ -205,9 +188,7 @@ class StarboardCog(commands.Cog):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
count = Star.objects(
|
count = Star.objects(guild=message.guild.id, starboard=starboard.id).count()
|
||||||
guild=message.guild.id, starboard=starboard.id
|
|
||||||
).count()
|
|
||||||
content = message.content
|
content = message.content
|
||||||
|
|
||||||
attachments = message.attachments
|
attachments = message.attachments
|
||||||
|
@ -232,9 +213,7 @@ class StarboardCog(commands.Cog):
|
||||||
url=message.jump_url,
|
url=message.jump_url,
|
||||||
icon_url=message.author.avatar_url,
|
icon_url=message.author.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=message.guild.name + " | " + message.channel.name)
|
||||||
text=message.guild.name + " | " + message.channel.name
|
|
||||||
)
|
|
||||||
if image_url:
|
if image_url:
|
||||||
embed.set_image(url=image_url)
|
embed.set_image(url=image_url)
|
||||||
|
|
||||||
|
@ -254,8 +233,7 @@ class StarboardCog(commands.Cog):
|
||||||
components[0]["components"][0]["disabled"] = True
|
components[0]["components"][0]["disabled"] = True
|
||||||
|
|
||||||
await com_ctx.edit_origin(
|
await com_ctx.edit_origin(
|
||||||
content="Message saved to Starboard.\n"
|
content=f"Message saved to Starboard.\nSee it in {starboard.mention}",
|
||||||
+ f"See it in {starboard.mention}",
|
|
||||||
components=components,
|
components=components,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -284,17 +262,14 @@ class StarboardCog(commands.Cog):
|
||||||
ctx: SlashContext,
|
ctx: SlashContext,
|
||||||
id: int,
|
id: int,
|
||||||
starboard: TextChannel,
|
starboard: TextChannel,
|
||||||
):
|
) -> None:
|
||||||
if not isinstance(starboard, TextChannel):
|
if not isinstance(starboard, TextChannel):
|
||||||
await ctx.send("Channel must be a TextChannel", hidden=True)
|
await ctx.send("Channel must be a TextChannel", hidden=True)
|
||||||
return
|
return
|
||||||
exists = Starboard.objects(
|
exists = Starboard.objects(channel=starboard.id, guild=ctx.guild.id).first()
|
||||||
channel=starboard.id, guild=ctx.guild.id
|
|
||||||
).first()
|
|
||||||
if not exists:
|
if not exists:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"Starboard does not exist in {starboard.mention}. "
|
f"Starboard does not exist in {starboard.mention}. Please create it first",
|
||||||
+ "Please create it first",
|
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -319,5 +294,6 @@ class StarboardCog(commands.Cog):
|
||||||
await ctx.send(f"Star {id} deleted")
|
await ctx.send(f"Star {id} deleted")
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add StarboardCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(StarboardCog(bot))
|
bot.add_cog(StarboardCog(bot))
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
|
"""J.A.R.V.I.S. Utility Cog."""
|
||||||
import re
|
import re
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
import string
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from discord import File, Guild, Role, User
|
from discord import File
|
||||||
|
from discord import Guild
|
||||||
|
from discord import Role
|
||||||
|
from discord import User
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
from discord_slash.utils.manage_commands import create_choice, create_option
|
from discord_slash import SlashContext
|
||||||
from PIL import Image, ImageDraw
|
from discord_slash.utils.manage_commands import create_choice
|
||||||
|
from discord_slash.utils.manage_commands import create_option
|
||||||
|
from PIL import Image
|
||||||
|
from PIL import ImageDraw
|
||||||
|
|
||||||
import jarvis
|
import jarvis
|
||||||
from jarvis import jarvis_self, logo
|
from jarvis import jarvis_self
|
||||||
|
from jarvis import logo
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
from jarvis.data.robotcamo import emotes, hk, names
|
from jarvis.data.robotcamo import emotes
|
||||||
from jarvis.utils import build_embed, convert_bytesize, get_repo_hash
|
from jarvis.data.robotcamo import hk
|
||||||
|
from jarvis.data.robotcamo import names
|
||||||
|
from jarvis.utils import build_embed
|
||||||
|
from jarvis.utils import convert_bytesize
|
||||||
|
from jarvis.utils import get_repo_hash
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +36,7 @@ class UtilCog(commands.Cog):
|
||||||
Mostly system utility functions, but may change over time
|
Mostly system utility functions, but may change over time
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: commands.Cog):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.config = get_config()
|
self.config = get_config()
|
||||||
|
|
||||||
|
@ -33,7 +45,7 @@ class UtilCog(commands.Cog):
|
||||||
description="Retrieve J.A.R.V.I.S. status",
|
description="Retrieve J.A.R.V.I.S. status",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _status(self, ctx):
|
async def _status(self, ctx: SlashContext) -> None:
|
||||||
title = "J.A.R.V.I.S. Status"
|
title = "J.A.R.V.I.S. Status"
|
||||||
desc = "All systems online"
|
desc = "All systems online"
|
||||||
color = "#98CCDA"
|
color = "#98CCDA"
|
||||||
|
@ -49,9 +61,7 @@ class UtilCog(commands.Cog):
|
||||||
fields.append(Field("PID", jarvis_self.pid))
|
fields.append(Field("PID", jarvis_self.pid))
|
||||||
fields.append(Field("Version", jarvis.__version__, False))
|
fields.append(Field("Version", jarvis.__version__, False))
|
||||||
fields.append(Field("Git Hash", get_repo_hash(), False))
|
fields.append(Field("Git Hash", get_repo_hash(), False))
|
||||||
embed = build_embed(
|
embed = build_embed(title=title, description=desc, fields=fields, color=color)
|
||||||
title=title, description=desc, fields=fields, color=color
|
|
||||||
)
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -59,12 +69,12 @@ class UtilCog(commands.Cog):
|
||||||
description="Get the current logo",
|
description="Get the current logo",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 30, commands.BucketType.channel)
|
@commands.cooldown(1, 30, commands.BucketType.channel)
|
||||||
async def _logo(self, ctx):
|
async def _logo(self, ctx: SlashContext) -> None:
|
||||||
lo = logo.get_logo(self.config.logo)
|
lo = logo.get_logo(self.config.logo)
|
||||||
await ctx.send(f"```\n{lo}\n```")
|
await ctx.send(f"```\n{lo}\n```")
|
||||||
|
|
||||||
@cog_ext.cog_slash(name="rchk", description="Robot Camo HK416")
|
@cog_ext.cog_slash(name="rchk", description="Robot Camo HK416")
|
||||||
async def _rchk(self, ctx: SlashContext):
|
async def _rchk(self, ctx: SlashContext) -> None:
|
||||||
await ctx.send(content=hk)
|
await ctx.send(content=hk)
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -79,11 +89,9 @@ class UtilCog(commands.Cog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _rcauto(self, ctx: SlashContext, text: str):
|
async def _rcauto(self, ctx: SlashContext, text: str) -> None:
|
||||||
to_send = ""
|
to_send = ""
|
||||||
if len(text) == 1 and not re.match(
|
if len(text) == 1 and not re.match(r"^[A-Z0-9-()$@!?^'#. ]$", text.upper()):
|
||||||
r"^[A-Z0-9-()$@!?^'#. ]$", text.upper()
|
|
||||||
):
|
|
||||||
await ctx.send("Please use ASCII characters.", hidden=True)
|
await ctx.send("Please use ASCII characters.", hidden=True)
|
||||||
return
|
return
|
||||||
for letter in text.upper():
|
for letter in text.upper():
|
||||||
|
@ -113,18 +121,14 @@ class UtilCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||||
async def _avatar(self, ctx, user: User = None):
|
async def _avatar(self, ctx: SlashContext, user: User = None) -> None:
|
||||||
if not user:
|
if not user:
|
||||||
user = ctx.author
|
user = ctx.author
|
||||||
|
|
||||||
avatar = user.avatar_url
|
avatar = user.avatar_url
|
||||||
embed = build_embed(
|
embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE")
|
||||||
title="Avatar", description="", fields=[], color="#00FFEE"
|
|
||||||
)
|
|
||||||
embed.set_image(url=avatar)
|
embed.set_image(url=avatar)
|
||||||
embed.set_author(
|
embed.set_author(name=f"{user.name}#{user.discriminator}", icon_url=avatar)
|
||||||
name=f"{user.name}#{user.discriminator}", icon_url=avatar
|
|
||||||
)
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -139,7 +143,7 @@ class UtilCog(commands.Cog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _roleinfo(self, ctx: SlashContext, role: Role):
|
async def _roleinfo(self, ctx: SlashContext, role: Role) -> None:
|
||||||
|
|
||||||
fields = [
|
fields = [
|
||||||
Field(name="ID", value=role.id),
|
Field(name="ID", value=role.id),
|
||||||
|
@ -148,9 +152,7 @@ class UtilCog(commands.Cog):
|
||||||
Field(name="Mention", value=f"`{role.mention}`"),
|
Field(name="Mention", value=f"`{role.mention}`"),
|
||||||
Field(name="Hoisted", value="Yes" if role.hoist else "No"),
|
Field(name="Hoisted", value="Yes" if role.hoist else "No"),
|
||||||
Field(name="Position", value=str(role.position)),
|
Field(name="Position", value=str(role.position)),
|
||||||
Field(
|
Field(name="Mentionable", value="Yes" if role.mentionable else "No"),
|
||||||
name="Mentionable", value="Yes" if role.mentionable else "No"
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
embed = build_embed(
|
embed = build_embed(
|
||||||
|
@ -192,7 +194,7 @@ class UtilCog(commands.Cog):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def _userinfo(self, ctx: SlashContext, user: User = None):
|
async def _userinfo(self, ctx: SlashContext, user: User = None) -> None:
|
||||||
if not user:
|
if not user:
|
||||||
user = ctx.author
|
user = ctx.author
|
||||||
user_roles = user.roles
|
user_roles = user.roles
|
||||||
|
@ -210,9 +212,7 @@ class UtilCog(commands.Cog):
|
||||||
),
|
),
|
||||||
Field(
|
Field(
|
||||||
name=f"Roles [{len(user_roles)}]",
|
name=f"Roles [{len(user_roles)}]",
|
||||||
value=" ".join([x.mention for x in user_roles])
|
value=" ".join([x.mention for x in user_roles]) if user_roles else "None",
|
||||||
if user_roles
|
|
||||||
else "None",
|
|
||||||
inline=False,
|
inline=False,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -224,23 +224,17 @@ class UtilCog(commands.Cog):
|
||||||
color=str(user_roles[0].color) if user_roles else "#FF0000",
|
color=str(user_roles[0].color) if user_roles else "#FF0000",
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_author(
|
embed.set_author(name=f"{user.name}#{user.discriminator}", icon_url=user.avatar_url)
|
||||||
name=f"{user.name}#{user.discriminator}", icon_url=user.avatar_url
|
|
||||||
)
|
|
||||||
embed.set_thumbnail(url=user.avatar_url)
|
embed.set_thumbnail(url=user.avatar_url)
|
||||||
embed.set_footer(text=f"ID: {user.id}")
|
embed.set_footer(text=f"ID: {user.id}")
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@cog_ext.cog_slash(name="serverinfo", description="Get server info")
|
@cog_ext.cog_slash(name="serverinfo", description="Get server info")
|
||||||
async def _server_info(self, ctx: SlashContext):
|
async def _server_info(self, ctx: SlashContext) -> None:
|
||||||
guild: Guild = ctx.guild
|
guild: Guild = ctx.guild
|
||||||
|
|
||||||
owner = (
|
owner = f"{guild.owner.name}#{guild.owner.discriminator}" if guild.owner else "||`[redacted]`||"
|
||||||
f"{guild.owner.name}#{guild.owner.discriminator}"
|
|
||||||
if guild.owner
|
|
||||||
else "||`[redacted]`||"
|
|
||||||
)
|
|
||||||
|
|
||||||
region = guild.region
|
region = guild.region
|
||||||
categories = len(guild.categories)
|
categories = len(guild.categories)
|
||||||
|
@ -260,13 +254,9 @@ class UtilCog(commands.Cog):
|
||||||
Field(name="Roles", value=roles),
|
Field(name="Roles", value=roles),
|
||||||
]
|
]
|
||||||
if len(role_list) < 1024:
|
if len(role_list) < 1024:
|
||||||
fields.append(
|
fields.append(Field(name="Role List", value=role_list, inline=False))
|
||||||
Field(name="Role List", value=role_list, inline=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
embed = build_embed(
|
embed = build_embed(title="", description="", fields=fields, timestamp=guild.created_at)
|
||||||
title="", description="", fields=fields, timestamp=guild.created_at
|
|
||||||
)
|
|
||||||
|
|
||||||
embed.set_author(name=guild.name, icon_url=guild.icon_url)
|
embed.set_author(name=guild.name, icon_url=guild.icon_url)
|
||||||
embed.set_thumbnail(url=guild.icon_url)
|
embed.set_thumbnail(url=guild.icon_url)
|
||||||
|
@ -302,13 +292,9 @@ class UtilCog(commands.Cog):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 15, type=commands.BucketType.user)
|
@commands.cooldown(1, 15, type=commands.BucketType.user)
|
||||||
async def _pw_gen(
|
async def _pw_gen(self, ctx: SlashContext, length: int = 32, chars: int = 3) -> None:
|
||||||
self, ctx: SlashContext, length: int = 32, chars: int = 3
|
|
||||||
):
|
|
||||||
if length > 256:
|
if length > 256:
|
||||||
await ctx.send(
|
await ctx.send("Please limit password to 256 characters", hidden=True)
|
||||||
"Please limit password to 256 characters", hidden=True
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
choices = [
|
choices = [
|
||||||
string.ascii_letters,
|
string.ascii_letters,
|
||||||
|
@ -320,11 +306,12 @@ class UtilCog(commands.Cog):
|
||||||
pw = "".join(secrets.choice(choices[chars]) for i in range(length))
|
pw = "".join(secrets.choice(choices[chars]) for i in range(length))
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"Generated password:\n`{pw}`\n\n"
|
f"Generated password:\n`{pw}`\n\n"
|
||||||
+ '**WARNING: Once you press "Dismiss Message", '
|
'**WARNING: Once you press "Dismiss Message", '
|
||||||
+ "*the password is lost forever***",
|
"*the password is lost forever***",
|
||||||
hidden=True,
|
hidden=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add UtilCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(UtilCog(bot))
|
bot.add_cog(UtilCog(bot))
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
from random import randint
|
"""J.A.R.V.I.S. Verify Cog."""
|
||||||
|
from secrets import randint
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord_slash import ComponentContext, SlashContext, cog_ext
|
from discord_slash import cog_ext
|
||||||
|
from discord_slash import ComponentContext
|
||||||
|
from discord_slash import SlashContext
|
||||||
from discord_slash.model import ButtonStyle
|
from discord_slash.model import ButtonStyle
|
||||||
from discord_slash.utils import manage_components
|
from discord_slash.utils import manage_components
|
||||||
|
|
||||||
from jarvis.db.models import Setting
|
from jarvis.db.models import Setting
|
||||||
|
|
||||||
|
|
||||||
def create_layout():
|
def create_layout() -> list:
|
||||||
|
"""Create verify component layout."""
|
||||||
buttons = []
|
buttons = []
|
||||||
yes = randint(0, 2)
|
yes = randint(0, 2)
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
|
@ -27,7 +31,9 @@ def create_layout():
|
||||||
|
|
||||||
|
|
||||||
class VerifyCog(commands.Cog):
|
class VerifyCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Verify Cog."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@cog_ext.cog_slash(
|
@cog_ext.cog_slash(
|
||||||
|
@ -35,27 +41,24 @@ class VerifyCog(commands.Cog):
|
||||||
description="Verify that you've read the rules",
|
description="Verify that you've read the rules",
|
||||||
)
|
)
|
||||||
@commands.cooldown(1, 15, commands.BucketType.user)
|
@commands.cooldown(1, 15, commands.BucketType.user)
|
||||||
async def _verify(self, ctx: SlashContext):
|
async def _verify(self, ctx: SlashContext) -> None:
|
||||||
await ctx.defer()
|
await ctx.defer()
|
||||||
role = Setting.objects(guild=ctx.guild.id, setting="verified").first()
|
role = Setting.objects(guild=ctx.guild.id, setting="verified").first()
|
||||||
if not role:
|
if not role:
|
||||||
await ctx.send(
|
await ctx.send("This guild has not enabled verification", delete_after=5)
|
||||||
"This guild has not enabled verification", delete_after=5
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
if ctx.guild.get_role(role.value) in ctx.author.roles:
|
if ctx.guild.get_role(role.value) in ctx.author.roles:
|
||||||
await ctx.send("You are already verified.", delete_after=5)
|
await ctx.send("You are already verified.", delete_after=5)
|
||||||
return
|
return
|
||||||
components = create_layout()
|
components = create_layout()
|
||||||
message = await ctx.send(
|
message = await ctx.send(
|
||||||
content=f"{ctx.author.mention}, "
|
content=f"{ctx.author.mention}, please press the button that says `YES`.",
|
||||||
+ "please press the button that says `YES`.",
|
|
||||||
components=components,
|
components=components,
|
||||||
)
|
)
|
||||||
await message.delete(delay=15)
|
await message.delete(delay=15)
|
||||||
|
|
||||||
@cog_ext.cog_component(components=create_layout())
|
@cog_ext.cog_component(components=create_layout())
|
||||||
async def _process(self, ctx: ComponentContext):
|
async def _process(self, ctx: ComponentContext) -> None:
|
||||||
await ctx.defer(edit_origin=True)
|
await ctx.defer(edit_origin=True)
|
||||||
try:
|
try:
|
||||||
if ctx.author.id != ctx.origin_message.mentions[0].id:
|
if ctx.author.id != ctx.origin_message.mentions[0].id:
|
||||||
|
@ -68,33 +71,24 @@ class VerifyCog(commands.Cog):
|
||||||
for c in components:
|
for c in components:
|
||||||
for c2 in c["components"]:
|
for c2 in c["components"]:
|
||||||
c2["disabled"] = True
|
c2["disabled"] = True
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="verified").first()
|
||||||
guild=ctx.guild.id, setting="verified"
|
|
||||||
).first()
|
|
||||||
role = ctx.guild.get_role(setting.value)
|
role = ctx.guild.get_role(setting.value)
|
||||||
await ctx.author.add_roles(role, reason="Verification passed")
|
await ctx.author.add_roles(role, reason="Verification passed")
|
||||||
setting = Setting.objects(
|
setting = Setting.objects(guild=ctx.guild.id, setting="unverified").first()
|
||||||
guild=ctx.guild.id, setting="unverified"
|
|
||||||
).first()
|
|
||||||
if setting:
|
if setting:
|
||||||
role = ctx.guild.get_role(setting.value)
|
role = ctx.guild.get_role(setting.value)
|
||||||
await ctx.author.remove_roles(
|
await ctx.author.remove_roles(role, reason="Verification passed")
|
||||||
role, reason="Verification passed"
|
|
||||||
)
|
|
||||||
await ctx.edit_origin(
|
await ctx.edit_origin(
|
||||||
content=f"Welcome, {ctx.author.mention}. "
|
content=f"Welcome, {ctx.author.mention}. Please enjoy your stay.",
|
||||||
+ "Please enjoy your stay.",
|
components=manage_components.spread_to_rows(*components, max_in_row=5),
|
||||||
components=manage_components.spread_to_rows(
|
|
||||||
*components, max_in_row=5
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
await ctx.origin_message.delete(delay=5)
|
await ctx.origin_message.delete(delay=5)
|
||||||
else:
|
else:
|
||||||
await ctx.edit_origin(
|
await ctx.edit_origin(
|
||||||
content=f"{ctx.author.mention}, incorrect. "
|
content=f"{ctx.author.mention}, incorrect. Please press the button that says `YES`",
|
||||||
+ "Please press the button that says `YES`",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: commands.Bot) -> None:
|
||||||
|
"""Add VerifyCog to J.A.R.V.I.S."""
|
||||||
bot.add_cog(VerifyCog(bot))
|
bot.add_cog(VerifyCog(bot))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Load the config for J.A.R.V.I.S."""
|
||||||
from yaml import load
|
from yaml import load
|
||||||
|
|
||||||
from jarvis.db.models import Config as DBConfig
|
from jarvis.db.models import Config as DBConfig
|
||||||
|
@ -9,7 +10,10 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
def __new__(cls, *args, **kwargs):
|
"""Config singleton object for J.A.R.V.I.S."""
|
||||||
|
|
||||||
|
def __new__(cls, *args: list, **kwargs: dict):
|
||||||
|
"""Get the singleton config, or creates a new one."""
|
||||||
it = cls.__dict__.get("it")
|
it = cls.__dict__.get("it")
|
||||||
if it is not None:
|
if it is not None:
|
||||||
return it
|
return it
|
||||||
|
@ -24,33 +28,39 @@ class Config(object):
|
||||||
logo: str,
|
logo: str,
|
||||||
mongo: dict,
|
mongo: dict,
|
||||||
urls: dict,
|
urls: dict,
|
||||||
|
log_level: str = "WARNING",
|
||||||
cogs: list = None,
|
cogs: list = None,
|
||||||
events: bool = True,
|
events: bool = True,
|
||||||
gitlab_token: str = None,
|
gitlab_token: str = None,
|
||||||
max_messages: int = 1000,
|
max_messages: int = 1000,
|
||||||
):
|
) -> None:
|
||||||
|
"""Initialize the config object."""
|
||||||
self.token = token
|
self.token = token
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
self.logo = logo
|
self.logo = logo
|
||||||
self.mongo = mongo
|
self.mongo = mongo
|
||||||
self.urls = urls
|
self.urls = urls
|
||||||
|
self.log_level = log_level
|
||||||
self.cogs = cogs
|
self.cogs = cogs
|
||||||
self.events = events
|
self.events = events
|
||||||
self.max_messages = max_messages
|
self.max_messages = max_messages
|
||||||
self.gitlab_token = gitlab_token
|
self.gitlab_token = gitlab_token
|
||||||
|
|
||||||
def get_db_config(self):
|
def get_db_config(self) -> None:
|
||||||
|
"""Load the database config objects."""
|
||||||
config = DBConfig.objects()
|
config = DBConfig.objects()
|
||||||
for item in config:
|
for item in config:
|
||||||
setattr(self, item.key, item.value)
|
setattr(self, item.key, item.value)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_yaml(cls, y):
|
def from_yaml(cls, y: dict) -> "Config":
|
||||||
|
"""Load the yaml config file."""
|
||||||
instance = cls(**y)
|
instance = cls(**y)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
def get_config(path: str = "config.yaml") -> Config:
|
def get_config(path: str = "config.yaml") -> Config:
|
||||||
|
"""Get the config from the specified yaml file."""
|
||||||
if Config.__dict__.get("it"):
|
if Config.__dict__.get("it"):
|
||||||
return Config()
|
return Config()
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
|
@ -59,6 +69,7 @@ def get_config(path: str = "config.yaml") -> Config:
|
||||||
return Config.from_yaml(y)
|
return Config.from_yaml(y)
|
||||||
|
|
||||||
|
|
||||||
def reload_config():
|
def reload_config() -> None:
|
||||||
|
"""Force reload of the config singleton on next call."""
|
||||||
if "it" in Config.__dict__:
|
if "it" in Config.__dict__:
|
||||||
Config.__dict__.pop("it")
|
Config.__dict__.pop("it")
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""dbrand-specific data."""
|
||||||
shipping_lookup = [
|
shipping_lookup = [
|
||||||
{"country": "afghanistan", "code": "AF"},
|
{"country": "afghanistan", "code": "AF"},
|
||||||
{"country": "albania", "code": "AL"},
|
{"country": "albania", "code": "AL"},
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,4 @@
|
||||||
|
"""Robot Camo emote lookups."""
|
||||||
emotes = {
|
emotes = {
|
||||||
"A": 852317928572715038,
|
"A": 852317928572715038,
|
||||||
"B": 852317954975727679,
|
"B": 852317954975727679,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Unicode emoji data."""
|
||||||
import json
|
import json
|
||||||
from os import getcwd
|
from os import getcwd
|
||||||
from os import sep as s
|
from os import sep as s
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
|
"""J.A.R.V.I.S. database object for mongoengine."""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from mongoengine import Document
|
from mongoengine import Document
|
||||||
from mongoengine.fields import (
|
from mongoengine.fields import BooleanField
|
||||||
BooleanField,
|
from mongoengine.fields import DateTimeField
|
||||||
DateTimeField,
|
from mongoengine.fields import DictField
|
||||||
DictField,
|
from mongoengine.fields import DynamicField
|
||||||
DynamicField,
|
from mongoengine.fields import IntField
|
||||||
IntField,
|
from mongoengine.fields import ListField
|
||||||
ListField,
|
from mongoengine.fields import LongField
|
||||||
LongField,
|
from mongoengine.fields import StringField
|
||||||
StringField,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SnowflakeField(LongField):
|
class SnowflakeField(LongField):
|
||||||
|
"""Snowflake LongField Override."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Autopurge(Document):
|
class Autopurge(Document):
|
||||||
|
"""Autopurge database object."""
|
||||||
|
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
channel = SnowflakeField(required=True)
|
channel = SnowflakeField(required=True)
|
||||||
delay = IntField(min_value=1, max_value=300, default=30)
|
delay = IntField(min_value=1, max_value=300, default=30)
|
||||||
|
@ -28,6 +31,8 @@ class Autopurge(Document):
|
||||||
|
|
||||||
|
|
||||||
class Autoreact(Document):
|
class Autoreact(Document):
|
||||||
|
"""Autoreact database object."""
|
||||||
|
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
channel = SnowflakeField(required=True)
|
channel = SnowflakeField(required=True)
|
||||||
reactions = ListField(field=StringField())
|
reactions = ListField(field=StringField())
|
||||||
|
@ -38,6 +43,8 @@ class Autoreact(Document):
|
||||||
|
|
||||||
|
|
||||||
class Ban(Document):
|
class Ban(Document):
|
||||||
|
"""Ban database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
user = SnowflakeField(required=True)
|
user = SnowflakeField(required=True)
|
||||||
|
@ -53,6 +60,8 @@ class Ban(Document):
|
||||||
|
|
||||||
|
|
||||||
class Config(Document):
|
class Config(Document):
|
||||||
|
"""Config database object."""
|
||||||
|
|
||||||
key = StringField(required=True)
|
key = StringField(required=True)
|
||||||
value = DynamicField(required=True)
|
value = DynamicField(required=True)
|
||||||
|
|
||||||
|
@ -60,6 +69,8 @@ class Config(Document):
|
||||||
|
|
||||||
|
|
||||||
class Guess(Document):
|
class Guess(Document):
|
||||||
|
"""Guess database object."""
|
||||||
|
|
||||||
correct = BooleanField(default=False)
|
correct = BooleanField(default=False)
|
||||||
guess = StringField(max_length=800, required=True)
|
guess = StringField(max_length=800, required=True)
|
||||||
user = SnowflakeField(required=True)
|
user = SnowflakeField(required=True)
|
||||||
|
@ -68,6 +79,8 @@ class Guess(Document):
|
||||||
|
|
||||||
|
|
||||||
class Joke(Document):
|
class Joke(Document):
|
||||||
|
"""Joke database object."""
|
||||||
|
|
||||||
rid = StringField()
|
rid = StringField()
|
||||||
body = StringField()
|
body = StringField()
|
||||||
title = StringField()
|
title = StringField()
|
||||||
|
@ -79,6 +92,8 @@ class Joke(Document):
|
||||||
|
|
||||||
|
|
||||||
class Kick(Document):
|
class Kick(Document):
|
||||||
|
"""Kick database object."""
|
||||||
|
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
reason = StringField(max_length=100, required=True)
|
reason = StringField(max_length=100, required=True)
|
||||||
|
@ -89,6 +104,8 @@ class Kick(Document):
|
||||||
|
|
||||||
|
|
||||||
class Lock(Document):
|
class Lock(Document):
|
||||||
|
"""Lock database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
channel = SnowflakeField(required=True)
|
channel = SnowflakeField(required=True)
|
||||||
|
@ -101,6 +118,8 @@ class Lock(Document):
|
||||||
|
|
||||||
|
|
||||||
class Mute(Document):
|
class Mute(Document):
|
||||||
|
"""Mute database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
user = SnowflakeField(required=True)
|
user = SnowflakeField(required=True)
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
|
@ -113,6 +132,8 @@ class Mute(Document):
|
||||||
|
|
||||||
|
|
||||||
class Purge(Document):
|
class Purge(Document):
|
||||||
|
"""Purge database object."""
|
||||||
|
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
channel = SnowflakeField(required=True)
|
channel = SnowflakeField(required=True)
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
|
@ -123,6 +144,8 @@ class Purge(Document):
|
||||||
|
|
||||||
|
|
||||||
class Reminder(Document):
|
class Reminder(Document):
|
||||||
|
"""Reminder database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
user = SnowflakeField(required=True)
|
user = SnowflakeField(required=True)
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
|
@ -135,6 +158,8 @@ class Reminder(Document):
|
||||||
|
|
||||||
|
|
||||||
class Roleping(Document):
|
class Roleping(Document):
|
||||||
|
"""Roleping database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
role = SnowflakeField(required=True)
|
role = SnowflakeField(required=True)
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
|
@ -146,6 +171,8 @@ class Roleping(Document):
|
||||||
|
|
||||||
|
|
||||||
class Setting(Document):
|
class Setting(Document):
|
||||||
|
"""Setting database object."""
|
||||||
|
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
setting = StringField(required=True)
|
setting = StringField(required=True)
|
||||||
value = DynamicField()
|
value = DynamicField()
|
||||||
|
@ -154,6 +181,8 @@ class Setting(Document):
|
||||||
|
|
||||||
|
|
||||||
class Star(Document):
|
class Star(Document):
|
||||||
|
"""Star database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
index = IntField(required=True)
|
index = IntField(required=True)
|
||||||
message = SnowflakeField(required=True)
|
message = SnowflakeField(required=True)
|
||||||
|
@ -168,6 +197,8 @@ class Star(Document):
|
||||||
|
|
||||||
|
|
||||||
class Starboard(Document):
|
class Starboard(Document):
|
||||||
|
"""Starboard database object."""
|
||||||
|
|
||||||
channel = SnowflakeField(required=True)
|
channel = SnowflakeField(required=True)
|
||||||
guild = SnowflakeField(required=True)
|
guild = SnowflakeField(required=True)
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
|
@ -177,6 +208,8 @@ class Starboard(Document):
|
||||||
|
|
||||||
|
|
||||||
class Unban(Document):
|
class Unban(Document):
|
||||||
|
"""Unban database object."""
|
||||||
|
|
||||||
user = SnowflakeField(required=True)
|
user = SnowflakeField(required=True)
|
||||||
username = StringField(required=True)
|
username = StringField(required=True)
|
||||||
discrim = IntField(min_value=1, max_value=9999, required=True)
|
discrim = IntField(min_value=1, max_value=9999, required=True)
|
||||||
|
@ -189,6 +222,8 @@ class Unban(Document):
|
||||||
|
|
||||||
|
|
||||||
class Warning(Document):
|
class Warning(Document):
|
||||||
|
"""Warning database object."""
|
||||||
|
|
||||||
active = BooleanField(default=True)
|
active = BooleanField(default=True)
|
||||||
admin = SnowflakeField(required=True)
|
admin = SnowflakeField(required=True)
|
||||||
user = SnowflakeField(required=True)
|
user = SnowflakeField(required=True)
|
||||||
|
|
|
@ -1,29 +1,33 @@
|
||||||
|
"""J.A.R.V.I.S. guild event handler."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
from discord import Guild
|
||||||
|
from discord.ext.commands import Bot
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
|
|
||||||
from jarvis.db.models import Setting
|
from jarvis.db.models import Setting
|
||||||
|
|
||||||
|
|
||||||
class GuildEventHandler(object):
|
class GuildEventHandler(object):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. guild event handler."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.bot.add_listener(self.on_guild_join)
|
self.bot.add_listener(self.on_guild_join)
|
||||||
|
|
||||||
async def on_guild_join(self, guild):
|
async def on_guild_join(self, guild: Guild) -> None:
|
||||||
|
"""Handle on_guild_join event."""
|
||||||
general = find(lambda x: x.name == "general", guild.channels)
|
general = find(lambda x: x.name == "general", guild.channels)
|
||||||
if general and general.permissions_for(guild.me).send_messages:
|
if general and general.permissions_for(guild.me).send_messages:
|
||||||
user = self.bot.user
|
user = self.bot.user
|
||||||
await general.send(
|
await general.send(
|
||||||
f"Allow me to introduce myself. I am {user.mention}, a virtual "
|
f"Allow me to introduce myself. I am {user.mention}, a virtual "
|
||||||
+ "artificial intelligence, and I'm here to assist you with a "
|
"artificial intelligence, and I'm here to assist you with a "
|
||||||
+ "variety of tasks as best I can, "
|
"variety of tasks as best I can, "
|
||||||
+ "24 hours a day, seven days a week."
|
"24 hours a day, seven days a week."
|
||||||
)
|
)
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
await general.send(
|
await general.send("Importing all preferences from home interface...")
|
||||||
"Importing all preferences from home interface..."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set some default settings
|
# Set some default settings
|
||||||
_ = Setting(guild=guild.id, setting="massmention", value=5).save()
|
_ = Setting(guild=guild.id, setting="massmention", value=5).save()
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
|
"""J.A.R.V.I.S. Member event handler."""
|
||||||
from discord import Member
|
from discord import Member
|
||||||
|
from discord.ext.commands import Bot
|
||||||
|
|
||||||
from jarvis.db.models import Mute, Setting
|
from jarvis.db.models import Mute
|
||||||
|
from jarvis.db.models import Setting
|
||||||
|
|
||||||
|
|
||||||
class MemberEventHandler(object):
|
class MemberEventHandler(object):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Member event handler."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.bot.add_listener(self.on_member_join)
|
self.bot.add_listener(self.on_member_join)
|
||||||
|
|
||||||
async def on_member_join(self, user: Member):
|
async def on_member_join(self, user: Member) -> None:
|
||||||
|
"""Handle on_member_join event."""
|
||||||
guild = user.guild
|
guild = user.guild
|
||||||
mute = Mute.objects(guild=guild.id, user=user.id, active=True).first()
|
mute = Mute.objects(guild=guild.id, user=user.id, active=True).first()
|
||||||
if mute:
|
if mute:
|
||||||
mute_role = Setting.objects(guild=guild.id, setting="mute").first()
|
mute_role = Setting.objects(guild=guild.id, setting="mute").first()
|
||||||
role = guild.get_role(mute_role.value)
|
role = guild.get_role(mute_role.value)
|
||||||
await user.add_roles(
|
await user.add_roles(role, reason="User is still muted from prior mute")
|
||||||
role, reason="User is still muted from prior mute"
|
unverified = Setting.objects(guild=guild.id, setting="unverified").first()
|
||||||
)
|
|
||||||
unverified = Setting.objects(
|
|
||||||
guild=guild.id, setting="unverified"
|
|
||||||
).first()
|
|
||||||
if unverified:
|
if unverified:
|
||||||
role = guild.get_role(unverified.value)
|
role = guild.get_role(unverified.value)
|
||||||
if role not in user.roles:
|
if role not in user.roles:
|
||||||
await user.add_roles(
|
await user.add_roles(role, reason="User just joined and is unverified")
|
||||||
role, reason="User just joined and is unverified"
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
|
"""J.A.R.V.I.S. Message event handler."""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from discord import DMChannel, Message
|
from discord import DMChannel
|
||||||
|
from discord import Message
|
||||||
|
from discord.ext.commands import Bot
|
||||||
from discord.utils import find
|
from discord.utils import find
|
||||||
|
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
from jarvis.db.models import Autopurge, Autoreact, Roleping, Setting, Warning
|
from jarvis.db.models import Autopurge
|
||||||
|
from jarvis.db.models import Autoreact
|
||||||
|
from jarvis.db.models import Roleping
|
||||||
|
from jarvis.db.models import Setting
|
||||||
|
from jarvis.db.models import Warning
|
||||||
from jarvis.utils import build_embed
|
from jarvis.utils import build_embed
|
||||||
from jarvis.utils.field import Field
|
from jarvis.utils.field import Field
|
||||||
|
|
||||||
|
@ -15,19 +22,21 @@ invites = re.compile(
|
||||||
|
|
||||||
|
|
||||||
class MessageEventHandler(object):
|
class MessageEventHandler(object):
|
||||||
def __init__(self, bot):
|
"""J.A.R.V.I.S. Message event handler."""
|
||||||
|
|
||||||
|
def __init__(self, bot: Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.bot.add_listener(self.on_message)
|
self.bot.add_listener(self.on_message)
|
||||||
self.bot.add_listener(self.on_message_edit)
|
self.bot.add_listener(self.on_message_edit)
|
||||||
|
|
||||||
async def autopurge(self, message: Message):
|
async def autopurge(self, message: Message) -> None:
|
||||||
autopurge = Autopurge.objects(
|
"""Handle autopurge events."""
|
||||||
guild=message.guild.id, channel=message.channel.id
|
autopurge = Autopurge.objects(guild=message.guild.id, channel=message.channel.id).first()
|
||||||
).first()
|
|
||||||
if autopurge:
|
if autopurge:
|
||||||
await message.delete(delay=autopurge.delay)
|
await message.delete(delay=autopurge.delay)
|
||||||
|
|
||||||
async def autoreact(self, message: Message):
|
async def autoreact(self, message: Message) -> None:
|
||||||
|
"""Handle autoreact events."""
|
||||||
autoreact = Autoreact.objects(
|
autoreact = Autoreact.objects(
|
||||||
guild=message.guild.id,
|
guild=message.guild.id,
|
||||||
channel=message.channel.id,
|
channel=message.channel.id,
|
||||||
|
@ -36,15 +45,13 @@ class MessageEventHandler(object):
|
||||||
for reaction in autoreact.reactions:
|
for reaction in autoreact.reactions:
|
||||||
await message.add_reaction(reaction)
|
await message.add_reaction(reaction)
|
||||||
|
|
||||||
async def checks(self, message: Message):
|
async def checks(self, message: Message) -> None:
|
||||||
|
"""Other message checks."""
|
||||||
# #tech
|
# #tech
|
||||||
channel = find(
|
channel = find(lambda x: x.id == 599068193339736096, message.channel_mentions)
|
||||||
lambda x: x.id == 599068193339736096, message.channel_mentions
|
|
||||||
)
|
|
||||||
if channel and message.author.id == 293795462752894976:
|
if channel and message.author.id == 293795462752894976:
|
||||||
await channel.send(
|
await channel.send(
|
||||||
content="https://cdn.discordapp.com/attachments/"
|
content="https://cdn.discordapp.com/attachments/664621130044407838/805218508866453554/tech.gif"
|
||||||
+ "664621130044407838/805218508866453554/tech.gif"
|
|
||||||
)
|
)
|
||||||
content = re.sub(r"\s+", "", message.content)
|
content = re.sub(r"\s+", "", message.content)
|
||||||
match = invites.search(content)
|
match = invites.search(content)
|
||||||
|
@ -78,29 +85,23 @@ class MessageEventHandler(object):
|
||||||
fields=fields,
|
fields=fields,
|
||||||
)
|
)
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name=message.author.nick
|
name=message.author.nick if message.author.nick else message.author.name,
|
||||||
if message.author.nick
|
|
||||||
else message.author.name,
|
|
||||||
icon_url=message.author.avatar_url,
|
icon_url=message.author.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{message.author.name}#{message.author.discriminator} | {message.author.id}")
|
||||||
text=f"{message.author.name}#"
|
|
||||||
+ f"{message.author.discriminator} "
|
|
||||||
+ f"| {message.author.id}"
|
|
||||||
)
|
|
||||||
await message.channel.send(embed=embed)
|
await message.channel.send(embed=embed)
|
||||||
|
|
||||||
async def massmention(self, message: Message):
|
async def massmention(self, message: Message) -> None:
|
||||||
|
"""Handle massmention events."""
|
||||||
massmention = Setting.objects(
|
massmention = Setting.objects(
|
||||||
guild=message.guild.id,
|
guild=message.guild.id,
|
||||||
setting="massmention",
|
setting="massmention",
|
||||||
).first()
|
).first()
|
||||||
if (
|
if (
|
||||||
massmention
|
massmention
|
||||||
and massmention.value > 0
|
and massmention.value > 0 # noqa: W503
|
||||||
and len(message.mentions)
|
and len(message.mentions) - (1 if message.author in message.mentions else 0) # noqa: W503
|
||||||
- (1 if message.author in message.mentions else 0)
|
> massmention.value # noqa: W503
|
||||||
> massmention.value
|
|
||||||
):
|
):
|
||||||
_ = Warning(
|
_ = Warning(
|
||||||
active=True,
|
active=True,
|
||||||
|
@ -117,18 +118,14 @@ class MessageEventHandler(object):
|
||||||
fields=fields,
|
fields=fields,
|
||||||
)
|
)
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name=message.author.nick
|
name=message.author.nick if message.author.nick else message.author.name,
|
||||||
if message.author.nick
|
|
||||||
else message.author.name,
|
|
||||||
icon_url=message.author.avatar_url,
|
icon_url=message.author.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{message.author.name}#{message.author.discriminator} | {message.author.id}")
|
||||||
text=f"{message.author.name}#{message.author.discriminator} "
|
|
||||||
+ f"| {message.author.id}"
|
|
||||||
)
|
|
||||||
await message.channel.send(embed=embed)
|
await message.channel.send(embed=embed)
|
||||||
|
|
||||||
async def roleping(self, message: Message):
|
async def roleping(self, message: Message) -> None:
|
||||||
|
"""Handle roleping events."""
|
||||||
rolepings = Roleping.objects(guild=message.guild.id, active=True)
|
rolepings = Roleping.objects(guild=message.guild.id, active=True)
|
||||||
|
|
||||||
if not rolepings:
|
if not rolepings:
|
||||||
|
@ -152,9 +149,7 @@ class MessageEventHandler(object):
|
||||||
role_in_rolepings = list(filter(lambda x: x in roleping_ids, roles))
|
role_in_rolepings = list(filter(lambda x: x in roleping_ids, roles))
|
||||||
|
|
||||||
# Check if the user has the role, so they are allowed to ping it
|
# Check if the user has the role, so they are allowed to ping it
|
||||||
user_missing_role = any(
|
user_missing_role = any(x.id not in roleping_ids for x in message.author.roles)
|
||||||
x.id not in roleping_ids for x in message.author.roles
|
|
||||||
)
|
|
||||||
|
|
||||||
# Admins can ping whoever
|
# Admins can ping whoever
|
||||||
user_is_admin = message.author.guild_permissions.administrator
|
user_is_admin = message.author.guild_permissions.administrator
|
||||||
|
@ -165,19 +160,11 @@ class MessageEventHandler(object):
|
||||||
if message.author.id in roleping.bypass["users"]:
|
if message.author.id in roleping.bypass["users"]:
|
||||||
user_has_bypass = True
|
user_has_bypass = True
|
||||||
break
|
break
|
||||||
if any(
|
if any(role.id in roleping.bypass["roles"] for role in message.author.roles):
|
||||||
role.id in roleping.bypass["roles"]
|
|
||||||
for role in message.author.roles
|
|
||||||
):
|
|
||||||
user_has_bypass = True
|
user_has_bypass = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if (
|
if role_in_rolepings and user_missing_role and not user_is_admin and not user_has_bypass:
|
||||||
role_in_rolepings
|
|
||||||
and user_missing_role
|
|
||||||
and not user_is_admin
|
|
||||||
and not user_has_bypass
|
|
||||||
):
|
|
||||||
_ = Warning(
|
_ = Warning(
|
||||||
active=True,
|
active=True,
|
||||||
admin=get_config().client_id,
|
admin=get_config().client_id,
|
||||||
|
@ -199,30 +186,26 @@ class MessageEventHandler(object):
|
||||||
fields=fields,
|
fields=fields,
|
||||||
)
|
)
|
||||||
embed.set_author(
|
embed.set_author(
|
||||||
name=message.author.nick
|
name=message.author.nick if message.author.nick else message.author.name,
|
||||||
if message.author.nick
|
|
||||||
else message.author.name,
|
|
||||||
icon_url=message.author.avatar_url,
|
icon_url=message.author.avatar_url,
|
||||||
)
|
)
|
||||||
embed.set_footer(
|
embed.set_footer(text=f"{message.author.name}#{message.author.discriminator} | {message.author.id}")
|
||||||
text=f"{message.author.name}#{message.author.discriminator} "
|
|
||||||
+ f"| {message.author.id}"
|
|
||||||
)
|
|
||||||
await message.channel.send(embed=embed)
|
await message.channel.send(embed=embed)
|
||||||
|
|
||||||
async def on_message(self, message: Message):
|
async def on_message(self, message: Message) -> None:
|
||||||
if (
|
"""Handle on_message event. Calls other event handlers."""
|
||||||
not isinstance(message.channel, DMChannel)
|
if not isinstance(message.channel, DMChannel) and not message.author.bot:
|
||||||
and not message.author.bot
|
|
||||||
):
|
|
||||||
await self.autoreact(message)
|
await self.autoreact(message)
|
||||||
await self.massmention(message)
|
await self.massmention(message)
|
||||||
await self.roleping(message)
|
await self.roleping(message)
|
||||||
await self.autopurge(message)
|
await self.autopurge(message)
|
||||||
await self.checks(message)
|
await self.checks(message)
|
||||||
|
|
||||||
async def on_message_edit(self, before: Message, after: Message):
|
async def on_message_edit(self, before: Message, after: Message) -> None:
|
||||||
|
"""Handle on_message_edit event. Calls other event handlers."""
|
||||||
if not isinstance(after.channel, DMChannel) and not after.author.bot:
|
if not isinstance(after.channel, DMChannel) and not after.author.bot:
|
||||||
await self.massmention(after)
|
await self.massmention(after)
|
||||||
await self.roleping(after)
|
await self.roleping(after)
|
||||||
await self.checks(after)
|
await self.checks(after)
|
||||||
|
await self.roleping(after)
|
||||||
|
await self.checks(after)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""Logos for J.A.R.V.I.S."""
|
||||||
|
|
||||||
logo_doom = r"""
|
logo_doom = r"""
|
||||||
___ ___ ______ _ _ _____ _____
|
___ ___ ______ _ _ _____ _____
|
||||||
|_ | / _ \ | ___ \ | | | | |_ _| / ___|
|
|_ | / _ \ | ___ \ | | | | |_ _| / ___|
|
||||||
|
@ -82,7 +84,7 @@ logo_alligator = r"""
|
||||||
#+# #+# #+# #+# #+# #+# #+# #+# #+# #+#+#+# #+# #+# #+# #+# #+# #+#
|
#+# #+# #+# #+# #+# #+# #+# #+# #+# #+#+#+# #+# #+# #+# #+# #+# #+#
|
||||||
##### ### ### ### ### ### ### ### ### ### ########### ### ######## ###
|
##### ### ### ### ### ### ### ### ### ### ########### ### ######## ###
|
||||||
|
|
||||||
"""
|
""" # noqa: E501
|
||||||
|
|
||||||
logo_alligator2 = r"""
|
logo_alligator2 = r"""
|
||||||
|
|
||||||
|
@ -97,7 +99,8 @@ logo_alligator2 = r"""
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def get_logo(lo):
|
def get_logo(lo: str) -> str:
|
||||||
|
"""Get a logo."""
|
||||||
if "logo_" not in lo:
|
if "logo_" not in lo:
|
||||||
lo = "logo_" + lo
|
lo = "logo_" + lo
|
||||||
return globals()[lo] if lo in globals() else logo_alligator2
|
return globals()[lo] if lo in globals() else logo_alligator2
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
from jarvis.tasks import unban, unlock, unmute, unwarn
|
"""J.A.R.V.I.S. background task handlers."""
|
||||||
|
from jarvis.tasks import unban
|
||||||
|
from jarvis.tasks import unlock
|
||||||
|
from jarvis.tasks import unmute
|
||||||
|
from jarvis.tasks import unwarn
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init() -> None:
|
||||||
|
"""Start the background task handlers."""
|
||||||
unban.unban.start()
|
unban.unban.start()
|
||||||
unlock.unlock.start()
|
unlock.unlock.start()
|
||||||
unmute.unmute.start()
|
unmute.unmute.start()
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. unban background task handler."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from discord.ext.tasks import loop
|
from discord.ext.tasks import loop
|
||||||
|
|
||||||
import jarvis
|
import jarvis
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
from jarvis.db.models import Ban, Unban
|
from jarvis.db.models import Ban
|
||||||
|
from jarvis.db.models import Unban
|
||||||
|
|
||||||
jarvis_id = get_config().client_id
|
jarvis_id = get_config().client_id
|
||||||
|
|
||||||
|
|
||||||
@loop(minutes=10)
|
@loop(minutes=10)
|
||||||
async def unban():
|
async def unban() -> None:
|
||||||
|
"""J.A.R.V.I.S. unban background task."""
|
||||||
bans = Ban.objects(type="temp", active=True)
|
bans = Ban.objects(type="temp", active=True)
|
||||||
unbans = []
|
unbans = []
|
||||||
for ban in bans:
|
for ban in bans:
|
||||||
if ban.created_at + timedelta(
|
if ban.created_at + timedelta(hours=ban.duration) < datetime.utcnow() + timedelta(minutes=10):
|
||||||
hours=ban.duration
|
|
||||||
) < datetime.utcnow() + timedelta(minutes=10):
|
|
||||||
guild = await jarvis.jarvis.fetch_guild(ban.guild)
|
guild = await jarvis.jarvis.fetch_guild(ban.guild)
|
||||||
user = await jarvis.jarvis.fetch_user(ban.user)
|
user = await jarvis.jarvis.fetch_user(ban.user)
|
||||||
if user:
|
if user:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. unlock background task handler."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from discord.ext.tasks import loop
|
from discord.ext.tasks import loop
|
||||||
|
|
||||||
|
@ -7,13 +9,11 @@ from jarvis.db.models import Lock
|
||||||
|
|
||||||
|
|
||||||
@loop(minutes=1)
|
@loop(minutes=1)
|
||||||
async def unlock():
|
async def unlock() -> None:
|
||||||
|
"""J.A.R.V.I.S. unlock background task."""
|
||||||
locks = Lock.objects(active=True)
|
locks = Lock.objects(active=True)
|
||||||
for lock in locks:
|
for lock in locks:
|
||||||
if (
|
if lock.created_at + timedelta(minutes=lock.duration) < datetime.utcnow():
|
||||||
lock.created_at + timedelta(minutes=lock.duration)
|
|
||||||
< datetime.utcnow()
|
|
||||||
):
|
|
||||||
guild = await jarvis.jarvis.fetch_guild(lock.guild)
|
guild = await jarvis.jarvis.fetch_guild(lock.guild)
|
||||||
channel = await jarvis.jarvis.fetch_channel(lock.channel)
|
channel = await jarvis.jarvis.fetch_channel(lock.channel)
|
||||||
if channel:
|
if channel:
|
||||||
|
@ -21,8 +21,6 @@ async def unlock():
|
||||||
for role in roles:
|
for role in roles:
|
||||||
overrides = channel.overwrites_for(role)
|
overrides = channel.overwrites_for(role)
|
||||||
overrides.send_messages = None
|
overrides.send_messages = None
|
||||||
await channel.set_permissions(
|
await channel.set_permissions(role, overwrite=overrides, reason="Lock expired")
|
||||||
role, overwrite=overrides, reason="Lock expired"
|
|
||||||
)
|
|
||||||
lock.active = False
|
lock.active = False
|
||||||
lock.save()
|
lock.save()
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. unmute background task handler."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from discord.ext.tasks import loop
|
from discord.ext.tasks import loop
|
||||||
|
|
||||||
import jarvis
|
import jarvis
|
||||||
from jarvis.db.models import Mute, Setting
|
from jarvis.db.models import Mute
|
||||||
|
from jarvis.db.models import Setting
|
||||||
|
|
||||||
|
|
||||||
@loop(minutes=1)
|
@loop(minutes=1)
|
||||||
async def unmute():
|
async def unmute() -> None:
|
||||||
|
"""J.A.R.V.I.S. unmute background task."""
|
||||||
mutes = Mute.objects(duration__gt=0, active=True)
|
mutes = Mute.objects(duration__gt=0, active=True)
|
||||||
mute_roles = Setting.objects(setting="mute")
|
mute_roles = Setting.objects(setting="mute")
|
||||||
for mute in mutes:
|
for mute in mutes:
|
||||||
if (
|
if mute.created_at + timedelta(minutes=mute.duration) < datetime.utcnow():
|
||||||
mute.created_at + timedelta(minutes=mute.duration)
|
mute_role = [x.value for x in mute_roles if x.guild == mute.guild][0]
|
||||||
< datetime.utcnow()
|
|
||||||
):
|
|
||||||
mute_role = [x.value for x in mute_roles if x.guild == mute.guild][
|
|
||||||
0
|
|
||||||
]
|
|
||||||
guild = await jarvis.jarvis.fetch_guild(mute.guild)
|
guild = await jarvis.jarvis.fetch_guild(mute.guild)
|
||||||
role = guild.get_role(mute_role)
|
role = guild.get_role(mute_role)
|
||||||
user = await guild.fetch_member(mute.user)
|
user = await guild.fetch_member(mute.user)
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
from datetime import datetime, timedelta
|
"""J.A.R.V.I.S. unwarn background task handler."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from discord.ext.tasks import loop
|
from discord.ext.tasks import loop
|
||||||
|
|
||||||
import jarvis
|
|
||||||
from jarvis.db.models import Warning
|
from jarvis.db.models import Warning
|
||||||
|
|
||||||
|
|
||||||
@loop(hours=1)
|
@loop(hours=1)
|
||||||
async def unwarn():
|
async def unwarn() -> None:
|
||||||
|
"""J.A.R.V.I.S. unwarn background task."""
|
||||||
warns = Warning.objects(active=True)
|
warns = Warning.objects(active=True)
|
||||||
for warn in warns:
|
for warn in warns:
|
||||||
if (
|
if warn.created_at + timedelta(hours=warn.duration) < datetime.utcnow():
|
||||||
warn.created_at + timedelta(hours=warn.duration)
|
|
||||||
< datetime.utcnow()
|
|
||||||
):
|
|
||||||
warn.active = False
|
warn.active = False
|
||||||
warn.save()
|
warn.save()
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
"""J.A.R.V.I.S. Utility Functions."""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pkgutil import iter_modules
|
from pkgutil import iter_modules
|
||||||
|
|
||||||
import git
|
import git
|
||||||
from discord import Color, Embed
|
from discord import Color
|
||||||
|
from discord import Embed
|
||||||
|
from discord import Message
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
import jarvis.cogs
|
import jarvis.cogs
|
||||||
|
@ -12,17 +15,19 @@ from jarvis.config import get_config
|
||||||
__all__ = ["field", "db", "cachecog", "permissions"]
|
__all__ = ["field", "db", "cachecog", "permissions"]
|
||||||
|
|
||||||
|
|
||||||
def convert_bytesize(bytes: int) -> str:
|
def convert_bytesize(b: int) -> str:
|
||||||
bytes = float(bytes)
|
"""Convert bytes amount to human readable."""
|
||||||
|
b = float(b)
|
||||||
sizes = ["B", "KB", "MB", "GB", "TB", "PB"]
|
sizes = ["B", "KB", "MB", "GB", "TB", "PB"]
|
||||||
size = 0
|
size = 0
|
||||||
while bytes >= 1024 and size < len(sizes) - 1:
|
while b >= 1024 and size < len(sizes) - 1:
|
||||||
bytes = bytes / 1024
|
b = b / 1024
|
||||||
size += 1
|
size += 1
|
||||||
return "{:0.3f} {}".format(bytes, sizes[size])
|
return "{:0.3f} {}".format(b, sizes[size])
|
||||||
|
|
||||||
|
|
||||||
def unconvert_bytesize(size, ending: str):
|
def unconvert_bytesize(size: int, ending: str) -> int:
|
||||||
|
"""Convert human readable to bytes."""
|
||||||
ending = ending.upper()
|
ending = ending.upper()
|
||||||
sizes = ["B", "KB", "MB", "GB", "TB", "PB"]
|
sizes = ["B", "KB", "MB", "GB", "TB", "PB"]
|
||||||
if ending == "B":
|
if ending == "B":
|
||||||
|
@ -31,7 +36,8 @@ def unconvert_bytesize(size, ending: str):
|
||||||
return round(size * (1024 ** sizes.index(ending)))
|
return round(size * (1024 ** sizes.index(ending)))
|
||||||
|
|
||||||
|
|
||||||
def get_prefix(bot, message):
|
def get_prefix(bot: commands.Bot, message: Message) -> list:
|
||||||
|
"""Get bot prefixes."""
|
||||||
prefixes = ["!", "-", "%"]
|
prefixes = ["!", "-", "%"]
|
||||||
# if not message.guild:
|
# if not message.guild:
|
||||||
# return "?"
|
# return "?"
|
||||||
|
@ -39,13 +45,15 @@ def get_prefix(bot, message):
|
||||||
return commands.when_mentioned_or(*prefixes)(bot, message)
|
return commands.when_mentioned_or(*prefixes)(bot, message)
|
||||||
|
|
||||||
|
|
||||||
def get_extensions(path=jarvis.cogs.__path__) -> list:
|
def get_extensions(path: str = jarvis.cogs.__path__) -> list:
|
||||||
|
"""Get J.A.R.V.I.S. cogs."""
|
||||||
config = get_config()
|
config = get_config()
|
||||||
vals = config.cogs or [x.name for x in iter_modules(path)]
|
vals = config.cogs or [x.name for x in iter_modules(path)]
|
||||||
return ["jarvis.cogs.{}".format(x) for x in vals]
|
return ["jarvis.cogs.{}".format(x) for x in vals]
|
||||||
|
|
||||||
|
|
||||||
def parse_color_hex(hex: str) -> Color:
|
def parse_color_hex(hex: str) -> Color:
|
||||||
|
"""Convert a hex color to a d.py Color."""
|
||||||
hex = hex.lstrip("#")
|
hex = hex.lstrip("#")
|
||||||
rgb = tuple(int(hex[i : i + 2], 16) for i in (0, 2, 4)) # noqa: E203
|
rgb = tuple(int(hex[i : i + 2], 16) for i in (0, 2, 4)) # noqa: E203
|
||||||
return Color.from_rgb(*rgb)
|
return Color.from_rgb(*rgb)
|
||||||
|
@ -57,8 +65,9 @@ def build_embed(
|
||||||
fields: list,
|
fields: list,
|
||||||
color: str = "#FF0000",
|
color: str = "#FF0000",
|
||||||
timestamp: datetime = None,
|
timestamp: datetime = None,
|
||||||
**kwargs,
|
**kwargs: dict,
|
||||||
) -> Embed:
|
) -> Embed:
|
||||||
|
"""Embed builder utility function."""
|
||||||
if not timestamp:
|
if not timestamp:
|
||||||
timestamp = datetime.utcnow()
|
timestamp = datetime.utcnow()
|
||||||
embed = Embed(
|
embed = Embed(
|
||||||
|
@ -73,7 +82,8 @@ def build_embed(
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
|
|
||||||
def update():
|
def update() -> int:
|
||||||
|
"""J.A.R.V.I.S. update utility."""
|
||||||
repo = git.Repo(".")
|
repo = git.Repo(".")
|
||||||
dirty = repo.is_dirty()
|
dirty = repo.is_dirty()
|
||||||
current_hash = repo.head.object.hexsha
|
current_hash = repo.head.object.hexsha
|
||||||
|
@ -87,6 +97,7 @@ def update():
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def get_repo_hash():
|
def get_repo_hash() -> str:
|
||||||
|
"""J.A.R.V.I.S. current branch hash."""
|
||||||
repo = git.Repo(".")
|
repo = git.Repo(".")
|
||||||
return repo.head.object.hexsha
|
return repo.head.object.hexsha
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from datetime import datetime, timedelta
|
"""Cog wrapper for command caching."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.ext.tasks import loop
|
from discord.ext.tasks import loop
|
||||||
|
@ -7,27 +9,28 @@ from discord_slash import SlashContext
|
||||||
|
|
||||||
|
|
||||||
class CacheCog(commands.Cog):
|
class CacheCog(commands.Cog):
|
||||||
|
"""Cog wrapper for command caching."""
|
||||||
|
|
||||||
def __init__(self, bot: commands.Bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
self._expire_interaction.start()
|
self._expire_interaction.start()
|
||||||
|
|
||||||
def check_cache(self, ctx: SlashContext, **kwargs):
|
def check_cache(self, ctx: SlashContext, **kwargs: dict) -> dict:
|
||||||
|
"""Check the cache."""
|
||||||
if not kwargs:
|
if not kwargs:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
return find(
|
return find(
|
||||||
lambda x: x["command"] == ctx.subcommand_name
|
lambda x: x["command"] == ctx.subcommand_name # noqa: W503
|
||||||
and x["user"] == ctx.author.id
|
and x["user"] == ctx.author.id # noqa: W503
|
||||||
and x["guild"] == ctx.guild.id
|
and x["guild"] == ctx.guild.id # noqa: W503
|
||||||
and all(x[k] == v for k, v in kwargs.items()),
|
and all(x[k] == v for k, v in kwargs.items()), # noqa: W503
|
||||||
self.cache.values(),
|
self.cache.values(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@loop(minutes=1)
|
@loop(minutes=1)
|
||||||
async def _expire_interaction(self):
|
async def _expire_interaction(self) -> None:
|
||||||
keys = list(self.cache.keys())
|
keys = list(self.cache.keys())
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if self.cache[key]["timeout"] <= datetime.utcnow() + timedelta(
|
if self.cache[key]["timeout"] <= datetime.utcnow() + timedelta(minutes=1):
|
||||||
minutes=1
|
|
||||||
):
|
|
||||||
del self.cache[key]
|
del self.cache[key]
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
"""Embed field helper."""
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Field:
|
class Field:
|
||||||
|
"""Embed Field."""
|
||||||
|
|
||||||
name: Any
|
name: Any
|
||||||
value: Any
|
value: Any
|
||||||
inline: bool = True
|
inline: bool = True
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self) -> dict:
|
||||||
|
"""Convert Field to d.py field dict."""
|
||||||
return {"name": self.name, "value": self.value, "inline": self.inline}
|
return {"name": self.name, "value": self.value, "inline": self.inline}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
|
"""Permissions wrappers."""
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
from jarvis.config import get_config
|
from jarvis.config import get_config
|
||||||
|
|
||||||
|
|
||||||
def user_is_bot_admin():
|
def user_is_bot_admin() -> bool:
|
||||||
def predicate(ctx):
|
"""Check if a user is a J.A.R.V.I.S. admin."""
|
||||||
|
|
||||||
|
def predicate(ctx: commands.Context) -> bool:
|
||||||
|
"""Command check predicate."""
|
||||||
if getattr(get_config(), "admins", None):
|
if getattr(get_config(), "admins", None):
|
||||||
return ctx.author.id in get_config().admins
|
return ctx.author.id in get_config().admins
|
||||||
else:
|
else:
|
||||||
|
@ -13,12 +17,12 @@ def user_is_bot_admin():
|
||||||
return commands.check(predicate)
|
return commands.check(predicate)
|
||||||
|
|
||||||
|
|
||||||
def admin_or_permissions(**perms):
|
def admin_or_permissions(**perms: dict) -> bool:
|
||||||
|
"""Check if a user is an admin or has other perms."""
|
||||||
original = commands.has_permissions(**perms).predicate
|
original = commands.has_permissions(**perms).predicate
|
||||||
|
|
||||||
async def extended_check(ctx):
|
async def extended_check(ctx: commands.Context) -> bool:
|
||||||
return await commands.has_permissions(administrator=True).predicate(
|
"""Extended check predicate.""" # noqa: D401
|
||||||
ctx
|
return await commands.has_permissions(administrator=True).predicate(ctx) or await original(ctx)
|
||||||
) or await original(ctx)
|
|
||||||
|
|
||||||
return commands.check(extended_check)
|
return commands.check(extended_check)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
discord-py>=1.7, <2
|
|
||||||
psutil>=5.8, <6
|
|
||||||
GitPython>=3.1, <4
|
|
||||||
PyYaml>=5.4, <6
|
|
||||||
discord-py-slash-command>=2.3.2, <3
|
|
||||||
pymongo>=3.12.0, <4
|
|
||||||
opencv-python>=4.5, <5
|
|
||||||
ButtonPaginator>=0.0.3
|
ButtonPaginator>=0.0.3
|
||||||
Pillow>=8.2.0, <9
|
discord-py>=1.7, <2
|
||||||
python-gitlab>=2.9.0, <3
|
discord-py-slash-command>=2.3.2, <3
|
||||||
ulid-py>=1.1.0, <2
|
GitPython>=3.1, <4
|
||||||
mongoengine>=0.23, <1
|
mongoengine>=0.23, <1
|
||||||
|
opencv-python>=4.5, <5
|
||||||
|
Pillow>=8.2.0, <9
|
||||||
|
psutil>=5.8, <6
|
||||||
|
pymongo>=3.12.0, <4
|
||||||
|
python-gitlab>=2.9.0, <3
|
||||||
|
PyYaml>=5.4, <6
|
||||||
|
ulid-py>=1.1.0, <2
|
||||||
|
|
5
run.py
5
run.py
|
@ -1,6 +1,9 @@
|
||||||
#!/bin/python3
|
#!/bin/python3
|
||||||
|
# flake8: noqa
|
||||||
from importlib import reload as ireload
|
from importlib import reload as ireload
|
||||||
from multiprocessing import Process, Value, freeze_support
|
from multiprocessing import freeze_support
|
||||||
|
from multiprocessing import Process
|
||||||
|
from multiprocessing import Value
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue