Merge branch 'v1.0.0' into 'main'

V1.0.0

Closes #41, #40, #35, #39, #42, and #43

See merge request stark-industries/j.a.r.v.i.s.!3
This commit is contained in:
Zeva Rose 2021-07-11 23:47:38 +00:00
commit 75871202de
10 changed files with 252 additions and 62 deletions

View file

@ -159,6 +159,11 @@ async def on_message(message: Message):
text=f"{message.author.name}#{message.author.discriminator} | {message.author.id}"
)
await message.channel.send(embed=embed)
autopurge = db.jarvis.autopurge.find_one(
{"guild": message.guild.id, "channel": message.channel.id}
)
if autopurge:
await message.delete(delay=autopurge["delay"])
await jarvis.process_commands(message)

View file

@ -1,8 +1,9 @@
import re
from datetime import datetime, timedelta
from typing import Union
import pymongo
from discord import Member, Role, TextChannel, User
from discord import Member, Role, TextChannel, User, VoiceChannel
from discord.ext import commands
from discord.utils import find, get
from discord_slash import SlashContext, cog_ext
@ -73,13 +74,15 @@ class AdminCog(commands.Cog):
length: int = 4,
):
if not user or user == ctx.author:
await ctx.send("You cannot ban yourself.")
await ctx.send("You cannot ban yourself.", hidden=True)
return
if user == self.bot.user:
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", hidden=True)
return
if type == "temp" and length < 0:
await ctx.send("You cannot set a temp ban to < 0 hours.")
await ctx.send(
"You cannot set a temp ban to < 0 hours.", hidden=True
)
return
if not reason:
reason = (
@ -348,7 +351,8 @@ class AdminCog(commands.Cog):
if len(ban_messages) == 0:
message = "No bans matched the criteria."
else:
message = "Bans:\n```\n" + "\n".join(ban_messages) + "\n```"
message = "Active " if active else "Inactive "
message += "Bans:\n```\n" + "\n".join(ban_messages) + "\n```"
await ctx.send(message)
@cog_ext.cog_slash(
@ -373,10 +377,10 @@ class AdminCog(commands.Cog):
@admin_or_permissions(kick_members=True)
async def _kick(self, ctx: SlashContext, user: User, reason=None):
if not user or user == ctx.author:
await ctx.send("You cannot kick yourself.")
await ctx.send("You cannot kick yourself.", hidden=True)
return
if user == self.bot.user:
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", hidden=True)
return
if not reason:
reason = (
@ -420,7 +424,7 @@ class AdminCog(commands.Cog):
@admin_or_permissions(manage_messages=True)
async def _purge(self, ctx: SlashContext, amount: int = 10):
if amount < 1:
await ctx.send("Amount must be >= 1")
await ctx.send("Amount must be >= 1", hidden=True)
return
await ctx.defer()
channel = ctx.channel
@ -469,17 +473,18 @@ class AdminCog(commands.Cog):
):
await ctx.defer()
if user == ctx.author:
await ctx.send("You cannot mute yourself.")
await ctx.send("You cannot mute yourself.", hidden=True)
return
if user == self.bot.user:
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", hidden=True)
return
mute_setting = self.db.jarvis.settings.find_one(
{"guild": ctx.guild.id, "setting": "mute"}
)
if not mute_setting:
await ctx.send(
"Please configure a mute role with /settings mute <role> first"
"Please configure a mute role with /settings mute <role> first",
hidden=True,
)
return
role = get(ctx.guild.roles, id=mute_setting["value"])
@ -534,7 +539,8 @@ class AdminCog(commands.Cog):
if not mute_setting:
await ctx.send(
"Please configure a mute role with "
+ "/settings mute <role> first."
+ "/settings mute <role> first.",
hidden=True,
)
return
@ -542,7 +548,7 @@ class AdminCog(commands.Cog):
if role in user.roles:
await user.remove_roles(role, reason="Unmute")
else:
await ctx.send("User is not muted.")
await ctx.send("User is not muted.", hidden=True)
return
self.db.jarvis.mutes.update_many(
@ -556,24 +562,30 @@ class AdminCog(commands.Cog):
async def _lock_channel(
self,
channel: TextChannel,
channel: Union[TextChannel, VoiceChannel],
role: Role,
admin: User,
reason: str,
allow_send=False,
):
overrides = channel.overwrites_for(role)
if isinstance(channel, TextChannel):
overrides.send_messages = allow_send
elif isinstance(channel, VoiceChannel):
overrides.speak = allow_send
await channel.set_permissions(role, overwrite=overrides, reason=reason)
async def _unlock_channel(
self,
channel: TextChannel,
channel: Union[TextChannel, VoiceChannel],
role: Role,
admin: User,
):
overrides = channel.overwrites_for(role)
if isinstance(channel, TextChannel):
overrides.send_messages = None
elif isinstance(channel, VoiceChannel):
overrides.speak = None
await channel.set_permissions(role, overwrite=overrides)
@cog_ext.cog_slash(
@ -607,7 +619,7 @@ class AdminCog(commands.Cog):
ctx: SlashContext,
reason: str,
duration: int = 10,
channel: TextChannel = None,
channel: Union[TextChannel, VoiceChannel] = None,
):
await ctx.defer()
if not channel:
@ -647,7 +659,7 @@ class AdminCog(commands.Cog):
async def _unlock(
self,
ctx: SlashContext,
channel: TextChannel = None,
channel: Union[TextChannel, VoiceChannel] = None,
):
await ctx.defer()
if not channel:
@ -656,7 +668,7 @@ class AdminCog(commands.Cog):
{"guild": ctx.guild.id, "channel": channel.id, "active": True}
)
if not lock:
await ctx.send(f"{channel.mention} not locked.")
await ctx.send(f"{channel.mention} not locked.", hidden=True)
return
for role in ctx.guild.roles:
try:
@ -745,7 +757,7 @@ class AdminCog(commands.Cog):
self.db.jarvis.locks.find({"guild": ctx.guild.id, "active": True})
)
if not locks:
await ctx.send("No lockdown detected.")
await ctx.send("No lockdown detected.", hidden=True)
return
for channel in channels:
for role in roles:
@ -765,7 +777,7 @@ class AdminCog(commands.Cog):
)
if updates:
self.db.jarvis.locks.bulk_write(updates)
await ctx.send(f"Server unlocked")
await ctx.send("Server unlocked")
@cog_ext.cog_slash(
name="warn",
@ -883,6 +895,7 @@ class AdminCog(commands.Cog):
)
],
)
@commands.has_permissions(administrator=True)
async def _roleping_block(self, ctx: SlashContext, role: Role):
roles = self.db.jarvis.settings.find_one(
{"guild": ctx.guild.id, "setting": "roleping"}
@ -891,7 +904,9 @@ class AdminCog(commands.Cog):
roles = {"guild": ctx.guild.id, "setting": "roleping", "value": []}
if role.id in roles["value"]:
await ctx.send(f"Role `{role.name}` already in blocklist.")
await ctx.send(
f"Role `{role.name}` already in blocklist.", hidden=True
)
return
roles["value"].append(role.id)
self.db.jarvis.settings.update_one(
@ -915,16 +930,19 @@ class AdminCog(commands.Cog):
)
],
)
@commands.has_permissions(administrator=True)
async def _roleping_allow(self, ctx: SlashContext, role: Role):
roles = self.db.jarvis.settings.find_one(
{"guild": ctx.guild.id, "setting": "roleping"}
)
if not roles:
await ctx.send("No blocklist configured.")
await ctx.send("No blocklist configured.", hidden=True)
return
if role.id not in roles["value"]:
await ctx.send(f"Role `{role.name}` not in blocklist.")
await ctx.send(
f"Role `{role.name}` not in blocklist.", hidden=True
)
return
roles["value"].delete(role.id)
self.db.jarvis.settings.update_one(
@ -934,6 +952,111 @@ class AdminCog(commands.Cog):
)
await ctx.send(f"Role `{role.name}` removed blocklist.")
@cog_ext.cog_subcommand(
base="autopurge",
name="add",
description="Automatically purge messages after x seconds",
guild_ids=[418094694325813248, 578757004059738142, 862402786116763668],
options=[
create_option(
name="channel",
description="Channel to autopurge",
option_type=7,
required=True,
),
create_option(
name="delay",
description="Seconds to keep message before purge, default 30",
option_type=4,
required=False,
),
],
)
@admin_or_permissions(manage_messages=True)
async def _autopurge_add(
self, ctx: SlashContext, channel: TextChannel, delay: int = 30
):
autopurge = self.db.jarvis.autopurge.find(
{"guild": ctx.guild.id, "channel": channel.id}
)
if autopurge:
await ctx.send("Autopurge already exists.", hidden=True)
return
autopurge = {
"guild": ctx.guild.id,
"channel": channel.id,
"admin": ctx.author.id,
"delay": delay,
"time": datetime.utcnow(),
}
self.db.jarvis.autopurge.insert_one(autopurge)
await ctx.send(
f"Autopurge set up on {channel.mention}, "
+ f"delay is {delay} seconds"
)
@cog_ext.cog_subcommand(
base="autopurge",
name="remove",
description="Remove an autopurge",
guild_ids=[418094694325813248, 578757004059738142, 862402786116763668],
options=[
create_option(
name="channel",
description="Channel to remove from autopurge",
option_type=7,
required=True,
),
],
)
@admin_or_permissions(manage_messages=True)
async def _autopurge_remove(self, ctx: SlashContext, channel: TextChannel):
autopurge = self.db.jarvis.autopurge.find(
{"guild": ctx.guild.id, "channel": channel.id}
)
if not autopurge:
await ctx.send("Autopurge does not exist.", hidden=True)
return
self.db.jarvis.autopurge.delete_one({"_id": autopurge["_id"]})
await ctx.send(f"Autopurge removed from {channel.mention}.")
@cog_ext.cog_subcommand(
base="autopurge",
name="update",
description="Update autopurge on a channel",
guild_ids=[418094694325813248, 578757004059738142, 862402786116763668],
options=[
create_option(
name="channel",
description="Channel to update",
option_type=7,
required=True,
),
create_option(
name="delay",
description="New time to save",
option_type=4,
required=True,
),
],
)
@admin_or_permissions(manage_messages=True)
async def _autopurge_update(
self, ctx: SlashContext, channel: TextChannel, delay: int
):
autopurge = self.db.jarvis.autopurge.find(
{"guild": ctx.guild.id, "channel": channel.id}
)
if not autopurge:
await ctx.send("Autopurge does not exist.", hidden=True)
return
self.db.jarvis.autopurge.update_one(
{"_id": autopurge["_id"]}, {"$set": {"delay": delay}}
)
await ctx.send(
f"Autopurge delay updated to {delay} seconds on {channel.mention}."
)
def setup(bot):
bot.add_cog(AdminCog(bot))

View file

@ -4,7 +4,7 @@ from datetime import datetime
from discord import TextChannel
from discord.ext import commands
from discord.utils import find
from discord_slash import cog_ext
from discord_slash import SlashContext, cog_ext
from discord_slash.utils.manage_commands import create_option
import jarvis
@ -35,12 +35,17 @@ class AutoReactCog(commands.Cog):
],
)
@commands.has_permissions(administrator=True)
async def _autoreact_create(self, ctx, channel: TextChannel):
async def _autoreact_create(self, ctx: SlashContext, channel: TextChannel):
if not isinstance(channel, TextChannel):
await ctx.send("Channel must be a text channel", hidden=True)
return
exists = self.db.jarvis.autoreact.find_one(
{"guild": ctx.guild.id, "channel": channel.id}
)
if exists:
await ctx.send(f"Autoreact already exists for {channel.mention}.")
await ctx.send(
f"Autoreact already exists for {channel.mention}.", hidden=True
)
return
autoreact = {
@ -72,9 +77,11 @@ class AutoReactCog(commands.Cog):
{"guild": channel.guild.id, "channel": channel.id}
)
if exists:
await ctx.send(f"Autoreact remove from {channel.mention}")
await ctx.send(f"Autoreact removed from {channel.mention}")
else:
await ctx.send(f"Autoreact not found on {channel.mention}")
await ctx.send(
f"Autoreact not found on {channel.mention}", hidden=True
)
@cog_ext.cog_subcommand(
base="autoreact",
@ -104,13 +111,16 @@ class AutoReactCog(commands.Cog):
if not custom_emoji and not standard_emoji:
await ctx.send(
"Please use either an emote from this server"
+ " or a unicode emoji."
+ " or a unicode emoji.",
hidden=True,
)
return
if custom_emoji:
emoji_id = int(custom_emoji.group(1))
if not find(lambda x: x.id == emoji_id, ctx.guild.emojis):
await ctx.send("Please use a custom emote from this server.")
await ctx.send(
"Please use a custom emote from this server.", hidden=True
)
return
exists = self.db.jarvis.autoreact.find_one(
{"guild": ctx.guild.id, "channel": channel.id}
@ -123,12 +133,14 @@ class AutoReactCog(commands.Cog):
return
if emote in exists["reactions"]:
await ctx.send(
f"Emote already added to {channel.mention} autoreactions."
f"Emote already added to {channel.mention} autoreactions.",
hidden=True,
)
return
if len(exists["reactions"]) >= 20:
if len(exists["reactions"]) >= 5:
await ctx.send(
"Max number of reactions hit. Remove a different one to add this one"
"Max number of reactions hit. Remove a different one to add this one",
hidden=True,
)
return
exists["reactions"].append(emote)
@ -166,12 +178,14 @@ class AutoReactCog(commands.Cog):
if not exists:
await ctx.send(
"Please create autoreact first with "
+ f"/autoreact create {channel.mention}"
+ f"/autoreact create {channel.mention}",
hidden=True,
)
return
if emote not in exists["reactions"]:
await ctx.send(
f"{emote} not used in {channel.mention} autoreactions."
f"{emote} not used in {channel.mention} autoreactions.",
hidden=True,
)
return
exists["reactions"].remove(emote)
@ -203,7 +217,8 @@ class AutoReactCog(commands.Cog):
if not exists:
await ctx.send(
"Please create autoreact first with "
+ f"/autoreact create {channel.mention}"
+ f"/autoreact create {channel.mention}",
hidden=True,
)
return
message = ""

View file

@ -33,7 +33,7 @@ class CTCCog(commands.Cog):
async def _pw(self, ctx, guess: str):
guessed = self.db.ctc2.guesses.find_one({"guess": guess})
if guessed:
await ctx.send("Already guessed, dipshit.")
await ctx.send("Already guessed, dipshit.", hidden=True)
return
result = await self._session.post(self.url, data=guess)
message = ""

View file

@ -118,7 +118,7 @@ class DbrandCog(commands.Cog):
guild_ids=[862402786116763668, 578757004059738142],
description="(not)extortion",
)
async def _buy(self, ctx):
async def _extort(self, ctx):
await ctx.send(
"Be (not)extorted here: " + self.base_url + "not-extortion"
)

View file

@ -76,7 +76,8 @@ class DevCog(commands.Cog):
if method not in supported_hashes:
algo_txt = ", ".join(f"`{x}`" for x in supported_hashes)
await ctx.send(
"Unsupported hash algorithm. Supported:\n" + algo_txt
"Unsupported hash algorithm. Supported:\n" + algo_txt,
hidden=True,
)
return
if not data and len(ctx.message.attachments) == 0:
@ -119,14 +120,14 @@ class DevCog(commands.Cog):
async def _uuid(self, ctx, version: str = None, data: str = None):
if not version:
await ctx.send("Supported UUID versions: 3, 4, 5")
await ctx.send("Supported UUID versions: 3, 4, 5", hidden=True)
return
if version not in ["3", "4", "5"]:
await ctx.send("Supported UUID versions: 3, 4, 5")
await ctx.send("Supported UUID versions: 3, 4, 5", hidden=True)
return
version = int(version)
if version in [3, 5] and not data:
await ctx.send(f"UUID{version} requires data.")
await ctx.send(f"UUID{version} requires data.", hidden=True)
return
if version == 4:
await ctx.send(f"UUID4: `{uuid.uuid4()}`")
@ -233,7 +234,9 @@ class DevCog(commands.Cog):
if method not in self.base64_methods:
methods = ", ".join(f"`{x}`" for x in self.base64_methods)
await ctx.send(
"Usage: encode <method> <data>\nSupported methods:\n" + methods
"Usage: encode <method> <data>\nSupported methods:\n"
+ methods,
hidden=True,
)
return
method = getattr(base64, method + "encode")
@ -256,7 +259,9 @@ class DevCog(commands.Cog):
if method not in self.base64_methods:
methods = ", ".join(f"`{x}`" for x in self.base64_methods)
await ctx.send(
"Usage: decode <method> <data>\nSupported methods:\n" + methods
"Usage: decode <method> <data>\nSupported methods:\n"
+ methods,
hidden=True,
)
return
method = getattr(base64, method + "decode")

View file

@ -58,7 +58,9 @@ class JokeCog(commands.Cog):
)[0]
if result is None:
await ctx.send("Humor module failed. Please try again later.")
await ctx.send(
"Humor module failed. Please try again later.", hidden=True
)
return
emotes = re.findall(r"(&#x[a-fA-F0-9]*;)", result["body"])
for match in emotes:
@ -84,6 +86,21 @@ class JokeCog(commands.Cog):
else:
body += " " + word
desc = ""
title = result["title"]
if len(title) > 256:
new_title = ""
limit = False
for word in title.split(" "):
if len(new_title) + len(word) + 1 > 253 and not limit:
new_title += "..."
desc = "..."
limit = True
if not limit:
new_title += word + " "
else:
desc += word + " "
body_chunks.append(Field("", body, False))
fields = body_chunks
@ -94,8 +111,8 @@ class JokeCog(commands.Cog):
# ),
fields.append(Field("ID", result["id"]))
embed = build_embed(
title=result["title"],
description="",
title=title,
description=desc,
fields=fields,
url=f"https://reddit.com/r/jokes/comments/{result['id']}",
timestamp=datetime.fromtimestamp(result["created_utc"]),

View file

@ -358,6 +358,8 @@ class ModlogCog(commands.Cog):
{"guild": after.guild.id, "setting": "modlog"}
)
if modlog:
if before.content == after.content:
return
channel = before.guild.get_channel(modlog["value"])
fields = [
Field(
@ -425,12 +427,26 @@ class ModlogCog(commands.Cog):
channel = ctx.guild.get_channel(modlog["value"])
fields = [
Field("Command", ctx.name),
]
if ctx.args:
fields.append(
Field(
"Args",
" ".join(ctx.args) if ctx.args else "N/A",
" ".join(ctx.args),
False,
),
]
)
)
if ctx.kwargs:
kwargs_string = " ".join(
f"{k}: {ctx.kwargs[k]}" for k in ctx.kwargs
)
fields.append(
Field(
"Keyword Args",
kwargs_string,
False,
)
)
if ctx.subcommand_name:
fields.insert(1, Field("Subcommand", ctx.subcommand_name))
embed = build_embed(

View file

@ -66,14 +66,17 @@ class StarboardCog(commands.Cog):
async def _create(self, ctx, target: TextChannel):
if target not in ctx.guild.channels:
await ctx.send(
"Target channel not in guild. Choose an existing channel."
"Target channel not in guild. Choose an existing channel.",
hidden=True,
)
return
exists = self.db.jarvis.starboard.find_one(
{"target": target.id, "guild": ctx.guild.id}
)
if exists:
await ctx.send(f"Starboard already exists at {target.mention}.")
await ctx.send(
f"Starboard already exists at {target.mention}.", hidden=True
)
return
self.db.jarvis.starboard.insert_one(
@ -110,9 +113,13 @@ class StarboardCog(commands.Cog):
)
if deleted:
self.db.jarvis.stars.delete_many({"starboard": target.id})
await ctx.send(f"Starboard deleted from {target.mention}.")
await ctx.send(
f"Starboard deleted from {target.mention}.", hidden=True
)
else:
await ctx.send(f"Starboard not found in {target.mention}.")
await ctx.send(
f"Starboard not found in {target.mention}.", hidden=True
)
@cog_ext.cog_subcommand(
base="star",
@ -157,7 +164,8 @@ class StarboardCog(commands.Cog):
if not exists:
await ctx.send(
f"Starboard does not exist in {starboard.mention}. "
+ "Please create it first"
+ "Please create it first",
hidden=True,
)
return
@ -174,7 +182,8 @@ class StarboardCog(commands.Cog):
if exists:
await ctx.send(
f"Message already sent to Starboard {starboard.mention}"
f"Message already sent to Starboard {starboard.mention}",
hidden=True,
)
return

View file

@ -73,7 +73,7 @@ class UtilCog(commands.Cog):
async def _rcauto(self, ctx: SlashContext, text: str):
to_send = ""
if len(text) == 1 and not re.match(r"^[A-Z0-9-()$@!?^'#. ]$", text):
await ctx.send("Please use ASCII characters.")
await ctx.send("Please use ASCII characters.", hidden=True)
return
for letter in text.upper():
if letter == " ":
@ -85,7 +85,7 @@ class UtilCog(commands.Cog):
else:
to_send += f"<:{names[id]}:{id}>"
if len(to_send) > 2000:
await ctx.send("Too long.")
await ctx.send("Too long.", hidden=True)
else:
await ctx.send(to_send)