Compare commits

..

1 commit

Author SHA1 Message Date
fdbc4c0810
feat(issuecards): init
Some checks failed
Actions / Lint Code (Ruff & Pylint) (pull_request) Failing after 55s
Actions / Build Documentation (MkDocs) (pull_request) Failing after 1m1s
2025-03-28 09:56:44 -05:00
18 changed files with 554 additions and 335 deletions

38
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,38 @@
FROM ghcr.io/astral-sh/uv:0.5.30@sha256:bb74263127d6451222fe7f71b330edfb189ab1c98d7898df2401fbf4f272d9b9 AS uv
FROM python:3.11-slim@sha256:6ed5bff4d7d377e2a27d9285553b8c21cfccc4f00881de1b24c9bc8d90016e82 AS python
FROM code.forgejo.org/forgejo/runner:6.2.1@sha256:fecc96a111a15811a6887ce488e75718089f24599e613e93db8e54fe70b706e8 AS forgejo-runner
FROM mcr.microsoft.com/vscode/devcontainers/base:bookworm@sha256:6155a486f236fd5127b76af33086029d64f64cf49dd504accb6e5f949098eb7e
LABEL repository="www.coastalcommits.com/cswimr/SeaCogs"
LABEL maintainer="cswimr <seaswimmerthefsh@gmail.com>"
RUN apt-get update; \
apt-get install -y --no-install-recommends \
# Red-DiscordBot
build-essential \
git \
# PyNaCl
libsodium-dev \
# CFFI
libffi-dev \
# SSH repository support
openssh-client \
# Cog dependencies
# Audio
openjdk-17-jre-headless \
# PyLav
libaio1 \
libaio-dev \
# SeaUtils
dnsutils; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*
COPY --from=uv --chown=vscode: /uv /uvx /bin/
COPY --from=python --chown=vscode: /usr/local /usr/local
COPY --from=forgejo-runner --chown=vscode: /bin/forgejo-runner /bin/forgejo-runner
COPY --chown=vscode: .devcontainer/home/* /home/vscode/
RUN ln -s /usr/local/bin/python3.11 /usr/local/bin/python; \
python --version; \
python -m ensurepip

View file

@ -0,0 +1,52 @@
{
"name": "Red-DiscordBot: SeaCogs",
"build": {
"context": "..",
"dockerfile": "Dockerfile"
},
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"customizations": {
"vscode": {
"settings": {
"python.terminal.activateEnvInCurrentTerminal": true,
"python.terminal.activateEnvironment": true,
"terminal.integrated.defaultProfile.linux": "zsh",
"terminal.integrated.profiles.linux": {
"zsh": {
"path": "/bin/zsh"
}
}
},
"extensions": [
"charliermarsh.ruff",
"ms-azuretools.vscode-docker",
"ms-python.python",
"tekumara.typos-vscode",
"tamasfe.even-better-toml",
"redhat.vscode-yaml",
"DavidAnson.vscode-markdownlint",
"yy0931.vscode-sqlite3-editor",
"aaron-bond.better-comments",
"donjayamanne.githistory",
"eamodio.gitlens"
]
}
},
"containerEnv": {
"DISPLAY": "dummy",
"PYTHONUNBUFFERED": "True",
"UV_LINK_MODE": "copy",
"UV_PYTHON_PREFERENCE": "only-system",
"UV_PYTHON_DOWNLOADS": "never",
"PROJECT_DIR": "/workspaces/SeaCogs"
},
"mounts": [
"source=seacogs-persistent-data,target=/workspaces/SeaCogs/.data,type=volume"
],
"postCreateCommand": {
"Setup Virtual Environment": "uv sync --frozen && sudo chown -R vscode:vscode /workspaces/SeaCogs/.data && uv run redbot-setup --no-prompt --instance-name=local --data-path=/workspaces/SeaCogs/.data --backend=json"
},
"remoteUser": "vscode"
}

View file

@ -0,0 +1,3 @@
#!/usr/bin/env bash
alias runactions="forgejo-runner exec --default-actions-url=https://www.coastalcommits.com --gitea-instance=https://www.coastalcommits.com"

View file

@ -9,13 +9,13 @@ jobs:
lint:
name: Lint Code (Ruff & Pylint)
runs-on: docker
container: catthehacker/ubuntu:act-latest@sha256:70d7485966a50a639ddab37445fd27c2f0b5086ad4959ec3bba228ed394c1928
container: catthehacker/ubuntu:act-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
uses: https://github.com/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: "Setup uv"
uses: actions/setup-uv@22695119d769bdb6f7032ad67b9bca0ef8c4a174 # v5
uses: https://github.com/astral-sh/setup-uv@v5
with:
version: "latest"
enable-cache: true
@ -35,7 +35,7 @@ jobs:
docs:
name: Build Documentation (MkDocs)
runs-on: docker
container: catthehacker/ubuntu:act-latest@sha256:70d7485966a50a639ddab37445fd27c2f0b5086ad4959ec3bba228ed394c1928
container: catthehacker/ubuntu:act-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@ -43,7 +43,7 @@ jobs:
fetch-depth: 0
- name: "Setup uv"
uses: actions/setup-uv@22695119d769bdb6f7032ad67b9bca0ef8c4a174 # v5
uses: https://github.com/astral-sh/setup-uv@v5
with:
version: "latest"
enable-cache: true
@ -54,7 +54,7 @@ jobs:
run: uv sync --no-dev --group=documentation
- name: Set environment variables
uses: actions/env@1791216cd180e6578dd1d67fb8d2852b883a5f53 # v2
uses: actions/env@v2
- name: Build documentation
run: |
@ -74,7 +74,7 @@ jobs:
echo "${YELLOW}Deploying to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}...\n"
npx -p "@getmeli/cli" meli upload ./site \
--url "https://meli.csw.im" \
--url "https://pages.coastalcommits.com" \
--site "${{ vars.MELI_SITE_ID }}" \
--token "${{ secrets.MELI_TOKEN }}" \
--release "$CI_ACTION_REF_NAME_SLUG/${{ env.GITHUB_SHA }}" \

View file

@ -40,7 +40,7 @@ class Aurora(commands.Cog):
This cog stores all of its data in an SQLite database."""
__author__ = ["cswimr"]
__version__ = "2.1.5"
__version__ = "2.1.3"
__documentation__ = "https://seacogs.coastalcommits.com/aurora/"
async def red_delete_data_for_user(self, *, requester, user_id: int):
@ -70,8 +70,7 @@ class Aurora(commands.Cog):
await config.user_from_id(user_id).clear()
else:
logger.warning(
"Invalid requester passed to red_delete_data_for_user: %s",
requester,
"Invalid requester passed to red_delete_data_for_user: %s", requester
)
def __init__(self, bot: Red):
@ -136,8 +135,9 @@ class Aurora(commands.Cog):
if await config.guild(entry.guild).ignore_other_bots() is True:
if entry.user.bot or entry.target.bot:
return
elif entry.user.id == self.bot.user.id:
return
else:
if entry.user.id == self.bot.user.id:
return
duration = "NULL"
@ -159,10 +159,10 @@ class Aurora(commands.Cog):
elif entry.action == discord.AuditLogAction.member_update:
if entry.after.timed_out_until is not None:
timed_out_until_aware = entry.after.timed_out_until.replace(
tzinfo=timezone.utc,
tzinfo=timezone.utc
)
duration_datetime = timed_out_until_aware - datetime.now(
tz=timezone.utc,
tz=timezone.utc
)
minutes = round(duration_datetime.total_seconds() / 60)
duration = timedelta(minutes=minutes)
@ -209,7 +209,7 @@ class Aurora(commands.Cog):
return
await interaction.response.send_message(
content=f"{target.mention} has recieved a note!\n**Reason** - `{reason}`",
content=f"{target.mention} has recieved a note!\n**Reason** - `{reason}`"
)
if silent is None:
@ -239,7 +239,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has received a note! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has received a note! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -268,7 +268,7 @@ class Aurora(commands.Cog):
return
await interaction.response.send_message(
content=f"{target.mention} has been warned!\n**Reason** - `{reason}`",
content=f"{target.mention} has been warned!\n**Reason** - `{reason}`"
)
if silent is None:
@ -298,7 +298,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been warned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been warned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -342,8 +342,7 @@ class Aurora(commands.Cog):
parsed_time = parse_timedelta(duration)
if parsed_time is None:
await interaction.response.send_message(
content=error("Please provide a valid duration!"),
ephemeral=True,
content=error("Please provide a valid duration!"), ephemeral=True
)
return
else:
@ -351,15 +350,12 @@ class Aurora(commands.Cog):
if role.id not in addrole_whitelist:
await interaction.response.send_message(
content=error("That role isn't whitelisted!"),
ephemeral=True,
content=error("That role isn't whitelisted!"), ephemeral=True
)
return
if not await check_moddable(
target,
interaction,
["moderate_members", "manage_roles"],
target, interaction, ["moderate_members", "manage_roles"]
):
return
@ -394,7 +390,7 @@ class Aurora(commands.Cog):
reason=f"Role added by {interaction.user.id}{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''} for: {reason}",
)
response: discord.WebhookMessage = await interaction.followup.send(
content=f"{target.mention} has been given the {role.mention} role{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`",
content=f"{target.mention} has been given the {role.mention} role{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`"
)
moderation_id = await mysql_log(
@ -452,8 +448,7 @@ class Aurora(commands.Cog):
parsed_time = parse_timedelta(duration)
if parsed_time is None:
await interaction.response.send_message(
content=error("Please provide a valid duration!"),
ephemeral=True,
content=error("Please provide a valid duration!"), ephemeral=True
)
return
else:
@ -461,15 +456,12 @@ class Aurora(commands.Cog):
if role.id not in addrole_whitelist:
await interaction.response.send_message(
content=error("That role isn't whitelisted!"),
ephemeral=True,
content=error("That role isn't whitelisted!"), ephemeral=True
)
return
if not await check_moddable(
target,
interaction,
["moderate_members", "manage_roles"],
target, interaction, ["moderate_members", "manage_roles"]
):
return
@ -504,7 +496,7 @@ class Aurora(commands.Cog):
reason=f"Role removed by {interaction.user.id}{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''} for: {reason}",
)
response: discord.WebhookMessage = await interaction.followup.send(
content=f"{target.mention} has had the {role.mention} role removed{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`",
content=f"{target.mention} has had the {role.mention} role removed{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`"
)
moderation_id = await mysql_log(
@ -561,24 +553,21 @@ class Aurora(commands.Cog):
parsed_time = parse_timedelta(duration, maximum=timedelta(days=28))
if parsed_time is None:
await interaction.response.send_message(
error("Please provide a valid duration!"),
ephemeral=True,
error("Please provide a valid duration!"), ephemeral=True
)
return
except commands.BadArgument:
await interaction.response.send_message(
error("Please provide a duration that is less than 28 days."),
ephemeral=True,
error("Please provide a duration that is less than 28 days."), ephemeral=True
)
return
await target.timeout(
parsed_time,
reason=f"Muted by {interaction.user.id} for: {reason}",
parsed_time, reason=f"Muted by {interaction.user.id} for: {reason}"
)
await interaction.response.send_message(
content=f"{target.mention} has been muted for {humanize_timedelta(timedelta=parsed_time)}!\n**Reason** - `{reason}`",
content=f"{target.mention} has been muted for {humanize_timedelta(timedelta=parsed_time)}!\n**Reason** - `{reason}`"
)
if silent is None:
@ -609,7 +598,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been muted for {humanize_timedelta(timedelta=parsed_time)}! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been muted for {humanize_timedelta(timedelta=parsed_time)}! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -647,15 +636,14 @@ class Aurora(commands.Cog):
if reason:
await target.timeout(
None,
reason=f"Unmuted by {interaction.user.id} for: {reason}",
None, reason=f"Unmuted by {interaction.user.id} for: {reason}"
)
else:
await target.timeout(None, reason=f"Unbanned by {interaction.user.id}")
reason = "No reason given."
await interaction.response.send_message(
content=f"{target.mention} has been unmuted!\n**Reason** - `{reason}`",
content=f"{target.mention} has been unmuted!\n**Reason** - `{reason}`"
)
if silent is None:
@ -685,7 +673,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been unmuted! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been unmuted! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -714,7 +702,7 @@ class Aurora(commands.Cog):
return
await interaction.response.send_message(
content=f"{target.mention} has been kicked!\n**Reason** - `{reason}`",
content=f"{target.mention} has been kicked!\n**Reason** - `{reason}`"
)
if silent is None:
@ -746,7 +734,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been kicked! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been kicked! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -762,7 +750,7 @@ class Aurora(commands.Cog):
Choice(name="1 Day", value=86400),
Choice(name="3 Days", value=259200),
Choice(name="7 Days", value=604800),
],
]
)
async def ban(
self,
@ -798,8 +786,7 @@ class Aurora(commands.Cog):
try:
await interaction.guild.fetch_ban(target)
await interaction.response.send_message(
content=error(f"{target.mention} is already banned!"),
ephemeral=True,
content=error(f"{target.mention} is already banned!"), ephemeral=True
)
return
except discord.errors.NotFound:
@ -809,21 +796,19 @@ class Aurora(commands.Cog):
parsed_time = parse_relativedelta(duration)
if parsed_time is None:
await interaction.response.send_message(
content=error("Please provide a valid duration!"),
ephemeral=True,
content=error("Please provide a valid duration!"), ephemeral=True
)
return
try:
parsed_time = timedelta_from_relativedelta(parsed_time)
except ValueError:
await interaction.response.send_message(
content=error("Please provide a valid duration!"),
ephemeral=True,
content=error("Please provide a valid duration!"), ephemeral=True
)
return
await interaction.response.send_message(
content=f"{target.mention} has been banned for {humanize_timedelta(timedelta=parsed_time)}!\n**Reason** - `{reason}`",
content=f"{target.mention} has been banned for {humanize_timedelta(timedelta=parsed_time)}!\n**Reason** - `{reason}`"
)
try:
@ -857,7 +842,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been banned for {humanize_timedelta(timedelta=parsed_time)}! (Case `#{moderation_id}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been banned for {humanize_timedelta(timedelta=parsed_time)}! (Case `#{moderation_id}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -865,14 +850,14 @@ class Aurora(commands.Cog):
await send_evidenceformat(interaction, case)
else:
await interaction.response.send_message(
content=f"{target.mention} has been banned!\n**Reason** - `{reason}`",
content=f"{target.mention} has been banned!\n**Reason** - `{reason}`"
)
if silent is None:
silent = not await config.guild(interaction.guild).dm_users()
if silent is False:
try:
embed = await message_factory(
embed = embed = await message_factory(
await self.bot.get_embed_color(interaction.channel),
guild=interaction.guild,
moderator=interaction.user,
@ -901,7 +886,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been banned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been banned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -933,25 +918,22 @@ class Aurora(commands.Cog):
await interaction.guild.fetch_ban(target)
except discord.errors.NotFound:
await interaction.response.send_message(
content=error(f"{target.mention} is not banned!"),
ephemeral=True,
content=error(f"{target.mention} is not banned!"), ephemeral=True
)
return
if reason:
await interaction.guild.unban(
target,
reason=f"Unbanned by {interaction.user.id} for: {reason}",
target, reason=f"Unbanned by {interaction.user.id} for: {reason}"
)
else:
await interaction.guild.unban(
target,
reason=f"Unbanned by {interaction.user.id}",
target, reason=f"Unbanned by {interaction.user.id}"
)
reason = "No reason given."
await interaction.response.send_message(
content=f"{target.mention} has been unbanned!\n**Reason** - `{reason}`",
content=f"{target.mention} has been unbanned!\n**Reason** - `{reason}`"
)
if silent is None:
@ -981,7 +963,7 @@ class Aurora(commands.Cog):
reason,
)
await interaction.edit_original_response(
content=f"{target.mention} has been unbanned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`",
content=f"{target.mention} has been unbanned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`"
)
await log(interaction, moderation_id)
@ -1019,28 +1001,42 @@ class Aurora(commands.Cog):
export: bool
Exports the server's entire moderation history to a JSON file"""
if ephemeral is None:
ephemeral = await config.user(interaction.user).history_ephemeral() or await config.guild(interaction.guild).history_ephemeral() or False
ephemeral = (
await config.user(interaction.user).history_ephemeral()
or await config.guild(interaction.guild).history_ephemeral()
or False
)
if inline is None:
inline = await config.user(interaction.user).history_inline() or await config.guild(interaction.guild).history_inline() or False
inline = (
await config.user(interaction.user).history_inline()
or await config.guild(interaction.guild).history_inline()
or False
)
if pagesize is None:
if inline is True:
pagesize = await config.user(interaction.user).history_inline_pagesize() or await config.guild(interaction.guild).history_inline_pagesize() or 6
pagesize = (
await config.user(interaction.user).history_inline_pagesize()
or await config.guild(interaction.guild).history_inline_pagesize()
or 6
)
else:
pagesize = await config.user(interaction.user).history_pagesize() or await config.guild(interaction.guild).history_pagesize() or 5
pagesize = (
await config.user(interaction.user).history_pagesize()
or await config.guild(interaction.guild).history_pagesize()
or 5
)
await interaction.response.defer(ephemeral=ephemeral)
permissions = check_permissions(
interaction.client.user,
["embed_links"],
interaction,
interaction.client.user, ["embed_links"], interaction
)
if permissions:
await interaction.followup.send(
error(
f"I do not have the `{permissions}` permission, required for this action.",
f"I do not have the `{permissions}` permission, required for this action."
),
ephemeral=True,
)
@ -1065,15 +1061,18 @@ class Aurora(commands.Cog):
cases.append(case)
try:
filename = str(data_manager.cog_data_path(cog_instance=self)) + str(os.sep) + f"moderation_{interaction.guild.id}.json"
filename = (
str(data_manager.cog_data_path(cog_instance=self))
+ str(os.sep)
+ f"moderation_{interaction.guild.id}.json"
)
with open(filename, "w", encoding="utf-8") as f:
json.dump(cases, f, indent=2)
await interaction.followup.send(
file=discord.File(
filename,
f"moderation_{interaction.guild.id}.json",
filename, f"moderation_{interaction.guild.id}.json"
),
ephemeral=ephemeral,
)
@ -1082,7 +1081,7 @@ class Aurora(commands.Cog):
except json.JSONDecodeError as e:
await interaction.followup.send(
content=error(
"An error occured while exporting the moderation history.\nError:\n",
"An error occured while exporting the moderation history.\nError:\n"
)
+ box(e, "py"),
ephemeral=ephemeral,
@ -1128,7 +1127,7 @@ class Aurora(commands.Cog):
embed = discord.Embed(color=await self.bot.get_embed_color(interaction.channel))
embed.set_author(icon_url=interaction.guild.icon.url, name="Infraction History")
embed.set_footer(
text=f"Page {page:,}/{page_quantity:,} | {case_quantity:,} Results",
text=f"Page {page:,}/{page_quantity:,} | {case_quantity:,} Results"
)
memory_dict = {}
@ -1137,30 +1136,33 @@ class Aurora(commands.Cog):
if case["target_id"] not in memory_dict:
if case["target_type"] == "USER":
memory_dict[str(case["target_id"])] = await fetch_user_dict(
interaction.client,
case["target_id"],
interaction.client, case["target_id"]
)
elif case["target_type"] == "CHANNEL":
memory_dict[str(case["target_id"])] = await fetch_channel_dict(
interaction.guild,
case["target_id"],
interaction.guild, case["target_id"]
)
target_user = memory_dict[str(case["target_id"])]
if case["target_type"] == "USER":
target_name = f"`{target_user['name']}`" if target_user["discriminator"] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`"
target_name = (
f"`{target_user['name']}`"
if target_user["discriminator"] == "0"
else f"`{target_user['name']}#{target_user['discriminator']}`"
)
elif case["target_type"] == "CHANNEL":
target_name = f"`{target_user['mention']}`"
else:
target_name = ""
if case["moderator_id"] not in memory_dict:
memory_dict[str(case["moderator_id"])] = await fetch_user_dict(
interaction.client,
case["moderator_id"],
interaction.client, case["moderator_id"]
)
moderator_user = memory_dict[str(case["moderator_id"])]
moderator_name = f"`{moderator_user['name']}`" if moderator_user["discriminator"] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
moderator_name = (
f"`{moderator_user['name']}`"
if moderator_user["discriminator"] == "0"
else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
)
field_name = f"Case #{case['moderation_id']:,} ({str.title(case['moderation_type'])})"
field_value = f"**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})"
@ -1175,15 +1177,20 @@ class Aurora(commands.Cog):
**{
unit: int(val)
for unit, val in zip(
["hours", "minutes", "seconds"],
case["duration"].split(":"),
["hours", "minutes", "seconds"], case["duration"].split(":")
)
},
}
)
duration_embed = (
f"{humanize_timedelta(timedelta=td)} | <t:{case['end_timestamp']}:R>"
if bool(case["expired"]) is False
else f"{humanize_timedelta(timedelta=td)} | Expired"
)
duration_embed = f"{humanize_timedelta(timedelta=td)} | <t:{case['end_timestamp']}:R>" if bool(case["expired"]) is False else f"{humanize_timedelta(timedelta=td)} | Expired"
field_value += f"\n**Duration:** {duration_embed}"
field_value += f"\n**Timestamp:** <t:{case['timestamp']}> | <t:{case['timestamp']}:R>"
field_value += (
f"\n**Timestamp:** <t:{case['timestamp']}> | <t:{case['timestamp']}:R>"
)
if case["role_id"] != "0":
role = interaction.guild.get_role(int(case["role_id"]))
@ -1201,10 +1208,7 @@ class Aurora(commands.Cog):
@app_commands.command(name="resolve")
async def resolve(
self,
interaction: discord.Interaction,
case: int,
reason: str = None,
self, interaction: discord.Interaction, case: int, reason: str = None
):
"""Resolve a specific case.
@ -1222,7 +1226,7 @@ class Aurora(commands.Cog):
if permissions:
await interaction.response.send_message(
error(
f"I do not have the `{permissions}` permission, required for this action.",
f"I do not have the `{permissions}` permission, required for this action."
),
ephemeral=True,
)
@ -1231,7 +1235,9 @@ class Aurora(commands.Cog):
database = connect()
cursor = database.cursor()
query_1 = f"SELECT * FROM moderation_{interaction.guild.id} WHERE moderation_id = ?;"
query_1 = (
f"SELECT * FROM moderation_{interaction.guild.id} WHERE moderation_id = ?;"
)
cursor.execute(query_1, (case,))
result_1 = cursor.fetchone()
if result_1 is None or case == 0:
@ -1247,7 +1253,7 @@ class Aurora(commands.Cog):
if result_2 is None:
await interaction.response.send_message(
content=error(
f"This moderation has already been resolved!\nUse `/case {case}` for more information.",
f"This moderation has already been resolved!\nUse `/case {case}` for more information."
),
ephemeral=True,
)
@ -1261,7 +1267,7 @@ class Aurora(commands.Cog):
if len(changes) > 25:
await interaction.response.send_message(
content=error(
"Due to limitations with Discord's embed system, you cannot edit a case more than 25 times.",
"Due to limitations with Discord's embed system, you cannot edit a case more than 25 times."
),
ephemeral=True,
)
@ -1273,7 +1279,7 @@ class Aurora(commands.Cog):
"timestamp": case_dict["timestamp"],
"reason": case_dict["reason"],
"user_id": case_dict["moderator_id"],
},
}
)
changes.append(
{
@ -1281,7 +1287,7 @@ class Aurora(commands.Cog):
"timestamp": int(time.time()),
"reason": reason,
"user_id": interaction.user.id,
},
}
)
if case_dict["moderation_type"] in ["UNMUTE", "UNBAN"]:
@ -1295,12 +1301,11 @@ class Aurora(commands.Cog):
if case_dict["moderation_type"] == "MUTE":
try:
member = await interaction.guild.fetch_member(
case_dict["target_id"],
case_dict["target_id"]
)
await member.timeout(
None,
reason=f"Case #{case:,} resolved by {interaction.user.id}",
None, reason=f"Case #{case:,} resolved by {interaction.user.id}"
)
except discord.NotFound:
pass
@ -1310,8 +1315,7 @@ class Aurora(commands.Cog):
user = await interaction.client.fetch_user(case_dict["target_id"])
await interaction.guild.unban(
user,
reason=f"Case #{case} resolved by {interaction.user.id}",
user, reason=f"Case #{case} resolved by {interaction.user.id}"
)
except discord.NotFound:
pass
@ -1336,8 +1340,7 @@ class Aurora(commands.Cog):
case_dict=await fetch_case(case, interaction.guild.id),
)
await interaction.response.send_message(
content=f"✅ Moderation #{case:,} resolved!",
embed=embed,
content=f"✅ Moderation #{case:,} resolved!", embed=embed
)
await log(interaction, case, resolved=True)
@ -1349,7 +1352,7 @@ class Aurora(commands.Cog):
export=[
Choice(name="Export as File", value="file"),
Choice(name="Export as Codeblock", value="codeblock"),
],
]
)
async def case(
self,
@ -1373,35 +1376,41 @@ class Aurora(commands.Cog):
export: bool
Export the case to a JSON file or codeblock"""
permissions = check_permissions(
interaction.client.user,
["embed_links"],
interaction,
interaction.client.user, ["embed_links"], interaction
)
if permissions:
await interaction.response.send_message(
error(
f"I do not have the `{permissions}` permission, required for this action.",
f"I do not have the `{permissions}` permission, required for this action."
),
ephemeral=True,
)
return
if ephemeral is None:
ephemeral = await config.user(interaction.user).history_ephemeral() or await config.guild(interaction.guild).history_ephemeral() or False
ephemeral = (
await config.user(interaction.user).history_ephemeral()
or await config.guild(interaction.guild).history_ephemeral()
or False
)
if case != 0:
case_dict = await fetch_case(case, interaction.guild.id)
if case_dict:
if export:
if export.value == "file" or len(str(case_dict)) > 1800:
filename = str(data_manager.cog_data_path(cog_instance=self)) + str(os.sep) + f"moderation_{interaction.guild.id}_case_{case}.json"
filename = (
str(data_manager.cog_data_path(cog_instance=self))
+ str(os.sep)
+ f"moderation_{interaction.guild.id}_case_{case}.json"
)
with open(filename, "w", encoding="utf-8") as f:
json.dump(case_dict, f, indent=2)
if export.value == "codeblock":
content = f"Case #{case:,} exported.\n" + warning(
"Case was too large to export as codeblock, so it has been uploaded as a `.json` file.",
"Case was too large to export as codeblock, so it has been uploaded as a `.json` file."
)
else:
content = f"Case #{case:,} exported."
@ -1418,41 +1427,34 @@ class Aurora(commands.Cog):
os.remove(filename)
return
await interaction.response.send_message(
content=box(json.dumps(case_dict, indent=2), "json"),
content=box(json.dumps(case_dict, indent=2), 'json'),
ephemeral=ephemeral,
)
return
if changes:
embed = await changes_factory(
interaction=interaction,
case_dict=case_dict,
interaction=interaction, case_dict=case_dict
)
await interaction.response.send_message(
embed=embed,
ephemeral=ephemeral,
embed=embed, ephemeral=ephemeral
)
elif evidenceformat:
content = await evidenceformat_factory(
interaction=interaction,
case_dict=case_dict,
interaction=interaction, case_dict=case_dict
)
await interaction.response.send_message(
content=content,
ephemeral=ephemeral,
content=content, ephemeral=ephemeral
)
else:
embed = await case_factory(
interaction=interaction,
case_dict=case_dict,
interaction=interaction, case_dict=case_dict
)
await interaction.response.send_message(
embed=embed,
ephemeral=ephemeral,
embed=embed, ephemeral=ephemeral
)
return
await interaction.response.send_message(
content=f"No case with case number `{case}` found.",
ephemeral=True,
content=f"No case with case number `{case}` found.", ephemeral=True
)
@app_commands.command(name="edit")
@ -1474,16 +1476,13 @@ class Aurora(commands.Cog):
duration: str
What is the new duration? Does not reapply the moderation if it has already expired.
"""
end_timestamp = None
permissions = check_permissions(
interaction.client.user,
["embed_links"],
interaction,
interaction.client.user, ["embed_links"], interaction
)
if permissions:
await interaction.response.send_message(
error(
f"I do not have the `{permissions}` permission, required for this action.",
f"I do not have the `{permissions}` permission, required for this action."
),
ephemeral=True,
)
@ -1497,25 +1496,26 @@ class Aurora(commands.Cog):
parsed_time = parse_timedelta(duration)
if parsed_time is None:
await interaction.response.send_message(
error("Please provide a valid duration!"),
ephemeral=True,
error("Please provide a valid duration!"), ephemeral=True
)
return
end_timestamp = case_dict["timestamp"] + parsed_time.total_seconds()
if case_dict["moderation_type"] == "MUTE":
if (time.time() - case_dict["timestamp"]) + parsed_time.total_seconds() > 2419200:
if (
time.time() - case_dict["timestamp"]
) + parsed_time.total_seconds() > 2419200:
await interaction.response.send_message(
error(
"Please provide a duration that is less than 28 days from the initial moderation.",
),
"Please provide a duration that is less than 28 days from the initial moderation."
)
)
return
try:
member = await interaction.guild.fetch_member(
case_dict["target_id"],
case_dict["target_id"]
)
await member.timeout(
@ -1529,7 +1529,7 @@ class Aurora(commands.Cog):
if len(changes) > 25:
await interaction.response.send_message(
content=error(
"Due to limitations with Discord's embed system, you cannot edit a case more than 25 times.",
"Due to limitations with Discord's embed system, you cannot edit a case more than 25 times."
),
ephemeral=True,
)
@ -1543,10 +1543,9 @@ class Aurora(commands.Cog):
"user_id": case_dict["moderator_id"],
"duration": case_dict["duration"],
"end_timestamp": case_dict["end_timestamp"],
},
}
)
if parsed_time:
assert end_timestamp is not None
changes.append(
{
"type": "EDIT",
@ -1555,7 +1554,7 @@ class Aurora(commands.Cog):
"user_id": interaction.user.id,
"duration": convert_timedelta_to_str(parsed_time),
"end_timestamp": end_timestamp,
},
}
)
else:
changes.append(
@ -1566,7 +1565,7 @@ class Aurora(commands.Cog):
"user_id": interaction.user.id,
"duration": case_dict["duration"],
"end_timestamp": case_dict["end_timestamp"],
},
}
)
database = connect()
@ -1603,8 +1602,7 @@ class Aurora(commands.Cog):
database.close()
return
await interaction.response.send_message(
content=error(f"No case with case number `{case}` found."),
ephemeral=True,
content=error(f"No case with case number `{case}` found."), ephemeral=True
)
@tasks.loop(minutes=1)
@ -1636,11 +1634,14 @@ class Aurora(commands.Cog):
unban_num = 0
for target_id, moderation_id in zip(target_ids, moderation_ids):
user: discord.User = await self.bot.fetch_user(target_id)
name = f"{user.name}#{user.discriminator}" if user.discriminator != "0" else user.name
name = (
f"{user.name}#{user.discriminator}"
if user.discriminator != "0"
else user.name
)
try:
await guild.unban(
user,
reason=f"Automatic unban from case #{moderation_id}",
user, reason=f"Automatic unban from case #{moderation_id}"
)
embed = await message_factory(
@ -1689,16 +1690,13 @@ class Aurora(commands.Cog):
role_ids = [row[2] for row in result]
for target_id, moderation_id, role_id in zip(
target_ids,
moderation_ids,
role_ids,
target_ids, moderation_ids, role_ids
):
try:
member = await guild.fetch_member(target_id)
await member.remove_roles(
Object(role_id),
reason=f"Automatic role removal from case #{moderation_id}",
Object(role_id), reason=f"Automatic role removal from case #{moderation_id}"
)
removerole_num = removerole_num + 1
@ -1727,16 +1725,13 @@ class Aurora(commands.Cog):
role_ids = [row[2] for row in result]
for target_id, moderation_id, role_id in zip(
target_ids,
moderation_ids,
role_ids,
target_ids, moderation_ids, role_ids
):
try:
member = await guild.fetch_member(target_id)
await member.add_roles(
Object(role_id),
reason=f"Automatic role addition from case #{moderation_id}",
Object(role_id), reason=f"Automatic role addition from case #{moderation_id}"
)
addrole_num = addrole_num + 1
@ -1832,11 +1827,15 @@ class Aurora(commands.Cog):
@commands.admin()
async def aurora_import_aurora(self, ctx: commands.Context):
"""Import moderation history from another bot using Aurora."""
if ctx.message.attachments and ctx.message.attachments[0].content_type == "application/json; charset=utf-8":
if (
ctx.message.attachments
and ctx.message.attachments[0].content_type
== "application/json; charset=utf-8"
):
message = await ctx.send(
warning(
"Are you sure you want to import moderations from another bot?\n**This will overwrite any moderations that already exist in this guild's moderation table.**\n*The import process will block the rest of your bot until it is complete.*",
),
"Are you sure you want to import moderations from another bot?\n**This will overwrite any moderations that already exist in this guild's moderation table.**\n*The import process will block the rest of your bot until it is complete.*"
)
)
await message.edit(view=ImportAuroraView(60, ctx, message))
else:
@ -1846,16 +1845,20 @@ class Aurora(commands.Cog):
@commands.admin()
async def aurora_import_galacticbot(self, ctx: commands.Context):
"""Import moderation history from GalacticBot."""
if ctx.message.attachments and ctx.message.attachments[0].content_type == "application/json; charset=utf-8":
if (
ctx.message.attachments
and ctx.message.attachments[0].content_type
== "application/json; charset=utf-8"
):
message = await ctx.send(
warning(
"Are you sure you want to import GalacticBot moderations?\n**This will overwrite any moderations that already exist in this guild's moderation table.**\n*The import process will block the rest of your bot until it is complete.*",
),
"Are you sure you want to import GalacticBot moderations?\n**This will overwrite any moderations that already exist in this guild's moderation table.**\n*The import process will block the rest of your bot until it is complete.*"
)
)
await message.edit(view=ImportGalacticBotView(60, ctx, message))
else:
await ctx.send(
error("Please provide a valid GalacticBot moderation export file."),
error("Please provide a valid GalacticBot moderation export file.")
)
@aurora.command(aliases=["tdc", "td", "timedeltaconvert"])

View file

@ -17,9 +17,13 @@ class ImportAuroraView(ui.View):
self.message: Message = message
@ui.button(label="Yes", style=ButtonStyle.success)
async def import_button_y(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def import_button_y(
self, interaction: Interaction, button: ui.Button
): # pylint: disable=unused-argument
await self.message.delete()
await interaction.response.send_message("Deleting original table...", ephemeral=True)
await interaction.response.send_message(
"Deleting original table...", ephemeral=True
)
database = connect()
cursor = database.cursor()
@ -97,10 +101,16 @@ class ImportAuroraView(ui.View):
await interaction.edit_original_response(content="Import complete.")
if failed_cases:
await interaction.edit_original_response(content="Import complete.\n" + warning("Failed to import the following cases:\n") + box(failed_cases))
await interaction.edit_original_response(
content="Import complete.\n"
+ warning("Failed to import the following cases:\n")
+ box(failed_cases)
)
@ui.button(label="No", style=ButtonStyle.danger)
async def import_button_n(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def import_button_n(
self, interaction: Interaction, button: ui.Button
): # pylint: disable=unused-argument
await self.message.edit(content="Import cancelled.", view=None)
await self.message.delete(10)
await self.ctx.message.delete(10)

View file

@ -16,9 +16,13 @@ class ImportGalacticBotView(ui.View):
self.message: Message = message
@ui.button(label="Yes", style=ButtonStyle.success)
async def import_button_y(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def import_button_y(
self, interaction: Interaction, button: ui.Button
): # pylint: disable=unused-argument
await self.message.delete()
await interaction.response.send_message("Deleting original table...", ephemeral=True)
await interaction.response.send_message(
"Deleting original table...", ephemeral=True
)
database = connect()
cursor = database.cursor()
@ -88,7 +92,9 @@ class ImportGalacticBotView(ui.View):
if resolved_by is None:
resolved_by = "?"
if resolved_reason is None:
resolved_reason = "Could not get resolve reason during moderation import."
resolved_reason = (
"Could not get resolve reason during moderation import."
)
if resolved_timestamp is None:
resolved_timestamp = timestamp
changes = [
@ -136,10 +142,16 @@ class ImportGalacticBotView(ui.View):
await interaction.edit_original_response(content="Import complete.")
if failed_cases:
await interaction.edit_original_response(content="Import complete.\n" + warning("Failed to import the following cases:\n") + box(failed_cases))
await interaction.edit_original_response(
content="Import complete.\n"
+ warning("Failed to import the following cases:\n")
+ box(failed_cases)
)
@ui.button(label="No", style=ButtonStyle.danger)
async def import_button_n(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def import_button_n(
self, interaction: Interaction, button: ui.Button
): # pylint: disable=unused-argument
await self.message.edit(content="Import cancelled.", view=None)
await self.message.delete(10)
await self.ctx.message.delete(10)

View file

@ -23,7 +23,7 @@ class Addrole(ui.View):
return
await interaction.response.defer()
async with config.guild(self.ctx.guild).addrole_whitelist() as addrole_whitelist:
addrole_whitelist: list # type hint
addrole_whitelist: list # type hint
for value in select.values:
if value.id in addrole_whitelist:
addrole_whitelist.remove(value.id)
@ -32,7 +32,7 @@ class Addrole(ui.View):
await interaction.message.edit(embed=await addrole_embed(self.ctx))
@ui.button(label="Clear", style=ButtonStyle.red, row=1)
async def clear(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def clear(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message(error("You must have the manage guild permission to clear the guild's addrole whitelist."), ephemeral=True)
return
@ -41,7 +41,7 @@ class Addrole(ui.View):
await interaction.message.edit(embed=await addrole_embed(self.ctx))
@ui.button(label="Close", style=ButtonStyle.gray)
async def close(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def close(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message(error("You can't do that!"), ephemeral=True)
return

View file

@ -17,7 +17,7 @@ class Guild(ui.View):
await self.message.edit(view=None)
@ui.button(label="Show Moderator", style=ButtonStyle.green, row=0)
async def show_moderator(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def show_moderator(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -27,7 +27,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="Use Discord Permissions", style=ButtonStyle.green, row=0)
async def use_discord_permissions(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def use_discord_permissions(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -37,7 +37,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="Respect Hierarchy", style=ButtonStyle.green, row=0)
async def respect_heirarchy(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def respect_heirarchy(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -47,7 +47,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="Ignore Modlog", style=ButtonStyle.green, row=0)
async def ignore_modlog(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def ignore_modlog(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -57,7 +57,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="Ignore Other Bots", style=ButtonStyle.green, row=0)
async def ignore_other_bots(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def ignore_other_bots(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -67,7 +67,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="DM Users", style=ButtonStyle.green, row=1)
async def dm_users(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def dm_users(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -77,7 +77,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="Auto Evidence Format", style=ButtonStyle.green, row=1)
async def auto_evidenceformat(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def auto_evidenceformat(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -87,7 +87,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="Ephemeral", style=ButtonStyle.green, row=1)
async def ephemeral(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def ephemeral(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -97,7 +97,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.button(label="History Inline", style=ButtonStyle.green, row=1)
async def inline(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def inline(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -107,11 +107,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.select(placeholder="History Pagesize", options=create_pagesize_options(), row=2)
async def pagesize(
self,
interaction: Interaction,
select: ui.Select,
):
async def pagesize(self, interaction: Interaction, select: ui.Select,):
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return
@ -123,11 +119,7 @@ class Guild(ui.View):
await interaction.message.edit(embed=await guild_embed(self.ctx))
@ui.select(placeholder="History Inline Pagesize", options=create_pagesize_options(), row=3)
async def inline_pagesize(
self,
interaction: Interaction,
select: ui.Select,
):
async def inline_pagesize(self, interaction: Interaction, select: ui.Select,):
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("You must have the manage guild permission to change this setting.", ephemeral=True)
return

View file

@ -23,7 +23,7 @@ class Immune(ui.View):
return
await interaction.response.defer()
async with config.guild(self.ctx.guild).immune_roles() as immune_roles:
immune_roles: list # type hint
immune_roles: list # type hint
for value in select.values:
if value.id in immune_roles:
immune_roles.remove(value.id)
@ -32,7 +32,7 @@ class Immune(ui.View):
await interaction.message.edit(embed=await immune_embed(self.ctx))
@ui.button(label="Clear", style=ButtonStyle.red, row=1)
async def clear(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def clear(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message(error("You must have the manage guild permission to clear the guild's immune roles."), ephemeral=True)
return
@ -41,7 +41,7 @@ class Immune(ui.View):
await interaction.message.edit(embed=await immune_embed(self.ctx))
@ui.button(label="Close", style=ButtonStyle.gray)
async def close(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def close(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if not interaction.user.guild_permissions.manage_guild and not interaction.user.guild_permissions.administrator:
await interaction.response.send_message(error("You can't do that!"), ephemeral=True)
return

View file

@ -17,7 +17,7 @@ class Overrides(ui.View):
await self.message.edit(view=None)
@ui.button(label="Auto Evidence Format", style=ButtonStyle.green, row=0)
async def auto_evidenceformat(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def auto_evidenceformat(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if self.ctx.author != interaction.user:
await interaction.response.send_message("You cannot change this setting for other users.", ephemeral=True)
return
@ -32,7 +32,7 @@ class Overrides(ui.View):
await interaction.message.edit(embed=await overrides_embed(self.ctx))
@ui.button(label="Ephemeral", style=ButtonStyle.green, row=0)
async def ephemeral(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def ephemeral(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if self.ctx.author != interaction.user:
await interaction.response.send_message("You cannot change this setting for other users.", ephemeral=True)
return
@ -47,7 +47,7 @@ class Overrides(ui.View):
await interaction.message.edit(embed=await overrides_embed(self.ctx))
@ui.button(label="Inline", style=ButtonStyle.green, row=0)
async def inline(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
async def inline(self, interaction: Interaction, button: ui.Button): # pylint: disable=unused-argument
if self.ctx.author != interaction.user:
await interaction.response.send_message("You cannot change this setting for other users.", ephemeral=True)
return
@ -62,11 +62,7 @@ class Overrides(ui.View):
await interaction.message.edit(embed=await overrides_embed(self.ctx))
@ui.select(placeholder="Inline Pagesize", options=create_pagesize_options(), row=1)
async def inline_pagesize(
self,
interaction: Interaction,
select: ui.Select,
):
async def inline_pagesize(self, interaction: Interaction, select: ui.Select,):
if self.ctx.author != interaction.user:
await interaction.response.send_message("You cannot change this setting for other users.", ephemeral=True)
return
@ -78,11 +74,7 @@ class Overrides(ui.View):
await interaction.message.edit(embed=await overrides_embed(self.ctx))
@ui.select(placeholder="Pagesize", options=create_pagesize_options(), row=2)
async def pagesize(
self,
interaction: Interaction,
select: ui.Select,
):
async def pagesize(self, interaction: Interaction, select: ui.Select,):
if self.ctx.author != interaction.user:
await interaction.response.send_message("You cannot change this setting for other users.", ephemeral=True)
return

View file

@ -8,18 +8,23 @@ from discord import Guild
from redbot.core import data_manager
from .logger import logger
from .utils import convert_timedelta_to_str, generate_dict, get_next_case_number
from .utils import (convert_timedelta_to_str, generate_dict,
get_next_case_number)
def connect() -> sqlite3.Connection:
"""Connects to the SQLite database, and returns a connection object."""
try:
return sqlite3.connect(database=data_manager.cog_data_path(raw_name="Aurora") / "aurora.db")
connection = sqlite3.connect(
database=data_manager.cog_data_path(raw_name="Aurora") / "aurora.db"
)
return connection
except sqlite3.OperationalError as e:
logger.error("Unable to access the SQLite database!\nError:\n%s", e.msg)
msg = f"Unable to access the SQLite Database!\n{e.msg}"
raise ConnectionRefusedError(msg) from e
raise ConnectionRefusedError(
f"Unable to access the SQLite Database!\n{e.msg}"
) from e
async def create_guild_table(guild: Guild):

View file

@ -75,9 +75,7 @@ async def message_factory(
if await config.guild(guild).show_moderator() and moderator is not None:
embed.add_field(
name="Moderator",
value=f"`{moderator.name} ({moderator.id})`",
inline=False,
name="Moderator", value=f"`{moderator.name} ({moderator.id})`", inline=False
)
embed.add_field(name="Reason", value=f"`{reason}`", inline=False)
@ -96,9 +94,7 @@ async def message_factory(
async def log_factory(
interaction: Interaction,
case_dict: dict,
resolved: bool = False,
interaction: Interaction, case_dict: dict, resolved: bool = False
) -> Embed:
"""This function creates a log embed from set parameters, meant for moderation logging.
@ -107,11 +103,14 @@ async def log_factory(
case_dict (dict): The case dictionary.
resolved (bool, optional): Whether the case is resolved or not. Defaults to False.
"""
target_name = ""
if resolved:
if case_dict["target_type"] == "USER":
target_user = await fetch_user_dict(interaction.client, case_dict["target_id"])
target_name = f"`{target_user['name']}`" if target_user["discriminator"] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`"
target_name = (
f"`{target_user['name']}`"
if target_user["discriminator"] == "0"
else f"`{target_user['name']}#{target_user['discriminator']}`"
)
elif case_dict["target_type"] == "CHANNEL":
target_user = await fetch_channel_dict(interaction.guild, case_dict["target_id"])
if target_user["mention"]:
@ -120,7 +119,11 @@ async def log_factory(
target_name = f"`{target_user['name']}`"
moderator_user = await fetch_user_dict(interaction.client, case_dict["moderator_id"])
moderator_name = f"`{moderator_user['name']}`" if moderator_user["discriminator"] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
moderator_name = (
f"`{moderator_user['name']}`"
if moderator_user["discriminator"] == "0"
else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
)
embed = Embed(
title=f"📕 Case #{case_dict['moderation_id']:,} Resolved",
@ -137,24 +140,40 @@ async def log_factory(
["hours", "minutes", "seconds"],
case_dict["duration"].split(":"),
)
},
}
)
duration_embed = (
f"{humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>"
if case_dict["expired"] == "0"
else str(humanize_timedelta(timedelta=td))
)
embed.description = (
embed.description
+ f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}"
)
duration_embed = f"{humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>" if case_dict["expired"] == "0" else str(humanize_timedelta(timedelta=td))
embed.description = embed.description + f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}"
embed.add_field(name="Reason", value=box(case_dict["reason"]), inline=False)
resolved_user = await fetch_user_dict(interaction.client, case_dict["resolved_by"])
resolved_name = resolved_user["name"] if resolved_user["discriminator"] == "0" else f"{resolved_user['name']}#{resolved_user['discriminator']}"
resolved_name = (
resolved_user["name"]
if resolved_user["discriminator"] == "0"
else f"{resolved_user['name']}#{resolved_user['discriminator']}"
)
embed.add_field(
name="Resolve Reason",
value=f"Resolved by `{resolved_name}` ({resolved_user['id']}) for:\n" + box(case_dict["resolve_reason"]),
value=f"Resolved by `{resolved_name}` ({resolved_user['id']}) for:\n"
+ box(case_dict["resolve_reason"]),
inline=False,
)
else:
if case_dict["target_type"] == "USER":
target_user = await fetch_user_dict(interaction.client, case_dict["target_id"])
target_name = f"`{target_user['name']}`" if target_user["discriminator"] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`"
target_name = (
f"`{target_user['name']}`"
if target_user["discriminator"] == "0"
else f"`{target_user['name']}#{target_user['discriminator']}`"
)
elif case_dict["target_type"] == "CHANNEL":
target_user = await fetch_channel_dict(interaction.guild, case_dict["target_id"])
if target_user["mention"]:
@ -163,7 +182,11 @@ async def log_factory(
target_name = f"`{target_user['name']}`"
moderator_user = await fetch_user_dict(interaction.client, case_dict["moderator_id"])
moderator_name = f"`{moderator_user['name']}`" if moderator_user["discriminator"] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
moderator_name = (
f"`{moderator_user['name']}`"
if moderator_user["discriminator"] == "0"
else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
)
embed = Embed(
title=f"📕 Case #{case_dict['moderation_id']:,}",
@ -179,9 +202,12 @@ async def log_factory(
["hours", "minutes", "seconds"],
case_dict["duration"].split(":"),
)
},
}
)
embed.description = (
embed.description
+ f"\n**Duration:** {humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>"
)
embed.description = embed.description + f"\n**Duration:** {humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>"
embed.add_field(name="Reason", value=box(case_dict["reason"]), inline=False)
return embed
@ -194,10 +220,13 @@ async def case_factory(interaction: Interaction, case_dict: dict) -> Embed:
interaction (Interaction): The interaction object.
case_dict (dict): The case dictionary.
"""
target_name = ""
if case_dict["target_type"] == "USER":
target_user = await fetch_user_dict(interaction.client, case_dict["target_id"])
target_name = f"`{target_user['name']}`" if target_user["discriminator"] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`"
target_name = (
f"`{target_user['name']}`"
if target_user["discriminator"] == "0"
else f"`{target_user['name']}#{target_user['discriminator']}`"
)
elif case_dict["target_type"] == "CHANNEL":
target_user = await fetch_channel_dict(interaction.guild, case_dict["target_id"])
if target_user["mention"]:
@ -206,7 +235,11 @@ async def case_factory(interaction: Interaction, case_dict: dict) -> Embed:
target_name = f"`{target_user['name']}`"
moderator_user = await fetch_user_dict(interaction.client, case_dict["moderator_id"])
moderator_name = f"`{moderator_user['name']}`" if moderator_user["discriminator"] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
moderator_name = (
f"`{moderator_user['name']}`"
if moderator_user["discriminator"] == "0"
else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
)
embed = Embed(
title=f"📕 Case #{case_dict['moderation_id']:,}",
@ -219,28 +252,41 @@ async def case_factory(interaction: Interaction, case_dict: dict) -> Embed:
**{
unit: int(val)
for unit, val in zip(
["hours", "minutes", "seconds"],
case_dict["duration"].split(":"),
["hours", "minutes", "seconds"], case_dict["duration"].split(":")
)
},
}
)
duration_embed = (
f"{humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>"
if bool(case_dict["expired"]) is False
else str(humanize_timedelta(timedelta=td))
)
duration_embed = f"{humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>" if bool(case_dict["expired"]) is False else str(humanize_timedelta(timedelta=td))
embed.description += f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}"
embed.description += f"\n**Changes:** {len(case_dict['changes']) - 1}" if case_dict["changes"] else "\n**Changes:** 0"
embed.description += (
f"\n**Changes:** {len(case_dict['changes']) - 1}"
if case_dict["changes"]
else "\n**Changes:** 0"
)
if case_dict["role_id"]:
embed.description += f"\n**Role:** <@&{case_dict['role_id']}>"
if case_dict["metadata"]:
if case_dict["metadata"]["imported_from"]:
embed.description += f"\n**Imported From:** {case_dict['metadata']['imported_from']}"
embed.description += (
f"\n**Imported From:** {case_dict['metadata']['imported_from']}"
)
embed.add_field(name="Reason", value=box(case_dict["reason"]), inline=False)
if case_dict["resolved"] == 1:
resolved_user = await fetch_user_dict(interaction.client, case_dict["resolved_by"])
resolved_name = f"`{resolved_user['name']}`" if resolved_user["discriminator"] == "0" else f"`{resolved_user['name']}#{resolved_user['discriminator']}`"
resolved_name = (
f"`{resolved_user['name']}`"
if resolved_user["discriminator"] == "0"
else f"`{resolved_user['name']}#{resolved_user['discriminator']}`"
)
embed.add_field(
name="Resolve Reason",
value=f"Resolved by {resolved_name} ({resolved_user['id']}) for:\n{box(case_dict['resolve_reason'])}",
@ -268,12 +314,15 @@ async def changes_factory(interaction: Interaction, case_dict: dict) -> Embed:
for change in case_dict["changes"]:
if change["user_id"] not in memory_dict:
memory_dict[str(change["user_id"])] = await fetch_user_dict(
interaction.client,
change["user_id"],
interaction.client, change["user_id"]
)
user = memory_dict[str(change["user_id"])]
name = user["name"] if user["discriminator"] == "0" else f"{user['name']}#{user['discriminator']}"
name = (
user["name"]
if user["discriminator"] == "0"
else f"{user['name']}#{user['discriminator']}"
)
timestamp = f"<t:{change['timestamp']}> | <t:{change['timestamp']}:R>"
@ -311,17 +360,24 @@ async def evidenceformat_factory(interaction: Interaction, case_dict: dict) -> s
interaction (Interaction): The interaction object.
case_dict (dict): The case dictionary.
"""
target_name = ""
if case_dict["target_type"] == "USER":
target_user = await fetch_user_dict(interaction.client, case_dict["target_id"])
target_name = target_user["name"] if target_user["discriminator"] == "0" else f"{target_user['name']}#{target_user['discriminator']}"
target_name = (
target_user["name"]
if target_user["discriminator"] == "0"
else f"{target_user['name']}#{target_user['discriminator']}"
)
elif case_dict["target_type"] == "CHANNEL":
target_user = await fetch_channel_dict(interaction.guild, case_dict["target_id"])
target_name = target_user["name"]
moderator_user = await fetch_user_dict(interaction.client, case_dict["moderator_id"])
moderator_name = moderator_user["name"] if moderator_user["discriminator"] == "0" else f"{moderator_user['name']}#{moderator_user['discriminator']}"
moderator_name = (
moderator_user["name"]
if moderator_user["discriminator"] == "0"
else f"{moderator_user['name']}#{moderator_user['discriminator']}"
)
content = f"Case: {case_dict['moderation_id']:,} ({str.title(case_dict['moderation_type'])})\nTarget: {target_name} ({target_user['id']})\nModerator: {moderator_name} ({moderator_user['id']})"
@ -363,11 +419,17 @@ async def overrides_embed(ctx: commands.Context) -> Embed:
}
override_str = [
"- " + bold("Auto Evidence Format: ") + get_bool_emoji(override_settings["auto_evidenceformat"]),
"- "
+ bold("Auto Evidence Format: ")
+ get_bool_emoji(override_settings["auto_evidenceformat"]),
"- " + bold("Ephemeral: ") + get_bool_emoji(override_settings["ephemeral"]),
"- " + bold("History Inline: ") + get_bool_emoji(override_settings["inline"]),
"- " + bold("History Inline Pagesize: ") + get_pagesize_str(override_settings["inline_pagesize"]),
"- " + bold("History Pagesize: ") + get_pagesize_str(override_settings["pagesize"]),
"- "
+ bold("History Inline Pagesize: ")
+ get_pagesize_str(override_settings["inline_pagesize"]),
"- "
+ bold("History Pagesize: ")
+ get_pagesize_str(override_settings["pagesize"]),
]
override_str = "\n".join(override_str)
@ -389,7 +451,7 @@ async def guild_embed(ctx: commands.Context) -> Embed:
guild_settings = {
"show_moderator": await config.guild(ctx.guild).show_moderator(),
"use_discord_permissions": await config.guild(
ctx.guild,
ctx.guild
).use_discord_permissions(),
"ignore_modlog": await config.guild(ctx.guild).ignore_modlog(),
"ignore_other_bots": await config.guild(ctx.guild).ignore_other_bots(),
@ -399,7 +461,7 @@ async def guild_embed(ctx: commands.Context) -> Embed:
"history_inline": await config.guild(ctx.guild).history_inline(),
"history_pagesize": await config.guild(ctx.guild).history_pagesize(),
"history_inline_pagesize": await config.guild(
ctx.guild,
ctx.guild
).history_inline_pagesize(),
"auto_evidenceformat": await config.guild(ctx.guild).auto_evidenceformat(),
"respect_hierarchy": await config.guild(ctx.guild).respect_hierarchy(),
@ -412,17 +474,37 @@ async def guild_embed(ctx: commands.Context) -> Embed:
channel = channel.mention
guild_str = [
"- " + bold("Show Moderator: ") + get_bool_emoji(guild_settings["show_moderator"]),
"- " + bold("Use Discord Permissions: ") + get_bool_emoji(guild_settings["use_discord_permissions"]),
"- " + bold("Respect Hierarchy: ") + get_bool_emoji(guild_settings["respect_hierarchy"]),
"- " + bold("Ignore Modlog: ") + get_bool_emoji(guild_settings["ignore_modlog"]),
"- " + bold("Ignore Other Bots: ") + get_bool_emoji(guild_settings["ignore_other_bots"]),
"- "
+ bold("Show Moderator: ")
+ get_bool_emoji(guild_settings["show_moderator"]),
"- "
+ bold("Use Discord Permissions: ")
+ get_bool_emoji(guild_settings["use_discord_permissions"]),
"- "
+ bold("Respect Hierarchy: ")
+ get_bool_emoji(guild_settings["respect_hierarchy"]),
"- "
+ bold("Ignore Modlog: ")
+ get_bool_emoji(guild_settings["ignore_modlog"]),
"- "
+ bold("Ignore Other Bots: ")
+ get_bool_emoji(guild_settings["ignore_other_bots"]),
"- " + bold("DM Users: ") + get_bool_emoji(guild_settings["dm_users"]),
"- " + bold("Auto Evidence Format: ") + get_bool_emoji(guild_settings["auto_evidenceformat"]),
"- " + bold("Ephemeral: ") + get_bool_emoji(guild_settings["history_ephemeral"]),
"- " + bold("History Inline: ") + get_bool_emoji(guild_settings["history_inline"]),
"- " + bold("History Pagesize: ") + get_pagesize_str(guild_settings["history_pagesize"]),
"- " + bold("History Inline Pagesize: ") + get_pagesize_str(guild_settings["history_inline_pagesize"]),
"- "
+ bold("Auto Evidence Format: ")
+ get_bool_emoji(guild_settings["auto_evidenceformat"]),
"- "
+ bold("Ephemeral: ")
+ get_bool_emoji(guild_settings["history_ephemeral"]),
"- "
+ bold("History Inline: ")
+ get_bool_emoji(guild_settings["history_inline"]),
"- "
+ bold("History Pagesize: ")
+ get_pagesize_str(guild_settings["history_pagesize"]),
"- "
+ bold("History Inline Pagesize: ")
+ get_pagesize_str(guild_settings["history_inline_pagesize"]),
"- " + bold("Log Channel: ") + channel,
]
guild_str = "\n".join(guild_str)
@ -446,21 +528,17 @@ async def addrole_embed(ctx: commands.Context) -> Embed:
for role in whitelist:
evalulated_role = ctx.guild.get_role(role) or error(f"`{role}` (Not Found)")
if isinstance(evalulated_role, Role):
roles.append(
{
"id": evalulated_role.id,
"mention": evalulated_role.mention,
"position": evalulated_role.position,
},
)
roles.append({
"id": evalulated_role.id,
"mention": evalulated_role.mention,
"position": evalulated_role.position
})
else:
roles.append(
{
"id": role,
"mention": error(f"`{role}` (Not Found)"),
"position": 0,
},
)
roles.append({
"id": role,
"mention": error(f"`{role}` (Not Found)"),
"position": 0
})
if roles:
roles = sorted(roles, key=lambda x: x["position"], reverse=True)
@ -471,7 +549,9 @@ async def addrole_embed(ctx: commands.Context) -> Embed:
e = await _config(ctx)
e.title += ": Addrole Whitelist"
e.description = "Use the select menu below to manage this guild's addrole whitelist."
e.description = (
"Use the select menu below to manage this guild's addrole whitelist."
)
if len(whitelist_str) > 4000 and len(whitelist_str) < 5000:
lines = whitelist_str.split("\n")
@ -501,21 +581,17 @@ async def immune_embed(ctx: commands.Context) -> Embed:
for role in immune_roles:
evalulated_role = ctx.guild.get_role(role) or error(f"`{role}` (Not Found)")
if isinstance(evalulated_role, Role):
roles.append(
{
"id": evalulated_role.id,
"mention": evalulated_role.mention,
"position": evalulated_role.position,
},
)
roles.append({
"id": evalulated_role.id,
"mention": evalulated_role.mention,
"position": evalulated_role.position
})
else:
roles.append(
{
"id": role,
"mention": error(f"`{role}` (Not Found)"),
"position": 0,
},
)
roles.append({
"id": role,
"mention": error(f"`{role}` (Not Found)"),
"position": 0
})
if roles:
roles = sorted(roles, key=lambda x: x["position"], reverse=True)

View file

@ -32,17 +32,24 @@ def check_permissions(
raise (KeyError)
for permission in permissions:
if not getattr(resolved_permissions, permission, False) and resolved_permissions.administrator is not True:
if (
not getattr(resolved_permissions, permission, False)
and resolved_permissions.administrator is not True
):
return permission
return False
async def check_moddable(target: Union[User, Member], interaction: Interaction, permissions: list) -> bool:
async def check_moddable(
target: Union[User, Member], interaction: Interaction, permissions: list
) -> bool:
"""Checks if a moderator can moderate a target."""
if check_permissions(interaction.client.user, permissions, guild=interaction.guild):
await interaction.response.send_message(
error(f"I do not have the `{permissions}` permission, required for this action."),
error(
f"I do not have the `{permissions}` permission, required for this action."
),
ephemeral=True,
)
return False
@ -50,30 +57,43 @@ async def check_moddable(target: Union[User, Member], interaction: Interaction,
if await config.guild(interaction.guild).use_discord_permissions() is True:
if check_permissions(interaction.user, permissions, guild=interaction.guild):
await interaction.response.send_message(
error(f"You do not have the `{permissions}` permission, required for this action."),
error(
f"You do not have the `{permissions}` permission, required for this action."
),
ephemeral=True,
)
return False
if interaction.user.id == target.id:
await interaction.response.send_message(content="You cannot moderate yourself!", ephemeral=True)
await interaction.response.send_message(
content="You cannot moderate yourself!", ephemeral=True
)
return False
if target.bot:
await interaction.response.send_message(content="You cannot moderate bots!", ephemeral=True)
await interaction.response.send_message(
content="You cannot moderate bots!", ephemeral=True
)
return False
if isinstance(target, Member):
if interaction.user.top_role <= target.top_role and await config.guild(interaction.guild).respect_hierarchy() is True:
await interaction.response.send_message(
content=error("You cannot moderate members with a higher role than you!"),
content=error(
"You cannot moderate members with a higher role than you!"
),
ephemeral=True,
)
return False
if interaction.guild.get_member(interaction.client.user.id).top_role <= target.top_role:
if (
interaction.guild.get_member(interaction.client.user.id).top_role
<= target.top_role
):
await interaction.response.send_message(
content=error("You cannot moderate members with a role higher than the bot!"),
content=error(
"You cannot moderate members with a role higher than the bot!"
),
ephemeral=True,
)
return False
@ -98,13 +118,15 @@ async def get_next_case_number(guild_id: str, cursor=None) -> int:
if not cursor:
database = connect()
cursor = database.cursor()
cursor.execute(f"SELECT moderation_id FROM `moderation_{guild_id}` ORDER BY moderation_id DESC LIMIT 1")
cursor.execute(
f"SELECT moderation_id FROM `moderation_{guild_id}` ORDER BY moderation_id DESC LIMIT 1"
)
result = cursor.fetchone()
return (result[0] + 1) if result else 1
def generate_dict(result) -> dict:
return {
case = {
"moderation_id": result[0],
"timestamp": result[1],
"moderation_type": result[2],
@ -122,6 +144,7 @@ def generate_dict(result) -> dict:
"changes": json.loads(result[14]),
"metadata": json.loads(result[15]),
}
return case
async def fetch_user_dict(client: commands.Bot, user_id: str) -> dict:
@ -148,6 +171,7 @@ async def fetch_user_dict(client: commands.Bot, user_id: str) -> dict:
"discriminator": "0",
}
return user_dict
@ -174,9 +198,11 @@ async def fetch_role_dict(guild: Guild, role_id: int) -> dict:
"""This function returns a dictionary containing either role information or a standard deleted role template."""
role = guild.get_role(int(role_id))
if not role:
pass
role_dict = {"id": role_id, "name": "Deleted Role"}
return {"id": role.id, "name": role.name}
role_dict = {"id": role.id, "name": role.name}
return role_dict
async def log(interaction: Interaction, moderation_id: int, resolved: bool = False) -> None:
@ -190,7 +216,9 @@ async def log(interaction: Interaction, moderation_id: int, resolved: bool = Fal
case = await fetch_case(moderation_id, interaction.guild.id)
if case:
embed = await log_factory(interaction=interaction, case_dict=case, resolved=resolved)
embed = await log_factory(
interaction=interaction, case_dict=case, resolved=resolved
)
try:
await logging_channel.send(embed=embed)
except Forbidden:
@ -201,7 +229,11 @@ async def send_evidenceformat(interaction: Interaction, case_dict: dict) -> None
"""This function sends an ephemeral message to the moderator who took the moderation action, with a pre-made codeblock for use in the mod-evidence channel."""
from .factory import evidenceformat_factory
send_evidence_bool = await config.user(interaction.user).auto_evidenceformat() or await config.guild(interaction.guild).auto_evidenceformat() or False
send_evidence_bool = (
await config.user(interaction.user).auto_evidenceformat()
or await config.guild(interaction.guild).auto_evidenceformat()
or False
)
if send_evidence_bool is False:
return
@ -242,19 +274,24 @@ def create_pagesize_options() -> list[SelectOption]:
label="Default",
value="default",
description="Reset the pagesize to the default value.",
),
)
)
options.extend(SelectOption(label=str(i), value=str(i), description=f"Set the pagesize to {i}") for i in range(1, 21))
for i in range(1, 21):
options.append(
SelectOption(
label=str(i),
value=str(i),
description=f"Set the pagesize to {i}.",
)
)
return options
def timedelta_from_relativedelta(relativedelta: rd) -> td:
"""Converts a relativedelta object to a timedelta object."""
now = datetime.now()
then = now - relativedelta
return now - then
def get_footer_image(coginstance: commands.Cog) -> File:
"""Returns the footer image for the embeds."""
image_path = data_manager.bundled_data_path(coginstance) / "arrow.png"

View file

@ -26,7 +26,7 @@ class Backup(commands.Cog):
__author__ = ["[cswimr](https://www.coastalcommits.com/cswimr)"]
__git__ = "https://www.coastalcommits.com/cswimr/SeaCogs"
__version__ = "1.1.4"
__version__ = "1.1.3"
__documentation__ = "https://seacogs.coastalcommits.com/backup/"
def __init__(self, bot: Red):
@ -49,6 +49,7 @@ class Backup(commands.Cog):
@commands.is_owner()
async def backup(self, ctx: commands.Context) -> None:
"""Backup your installed cogs."""
pass
@backup.command(name="export")
@commands.is_owner()

View file

@ -11,7 +11,7 @@
"hidden": false,
"disabled": false,
"min_bot_version": "3.5.6",
"max_bot_version": "3.5.17",
"max_bot_version": "3.5.16",
"min_python_version": [
3,
9,

View file

@ -21,7 +21,7 @@ class HotReload(commands.Cog):
__author__ = ["[cswimr](https://www.coastalcommits.com/cswimr)"]
__git__ = "https://www.coastalcommits.com/cswimr/SeaCogs"
__version__ = "1.4.2"
__version__ = "1.4.1"
__documentation__ = "https://seacogs.coastalcommits.com/hotreload/"
def __init__(self, bot: Red) -> None:
@ -60,7 +60,6 @@ class HotReload(commands.Cog):
]
return "\n".join(text)
# pylint: disable=protected-access
async def get_paths(self) -> Generator[Path, None, None]:
"""Retrieve user defined paths."""
cog_manager = self.bot._cog_mgr # noqa: SLF001 # We have to use this private method because there is no public API to get user defined paths
@ -92,6 +91,7 @@ class HotReload(commands.Cog):
@commands.group(name="hotreload")
async def hotreload_group(self, ctx: commands.Context) -> None:
"""HotReload configuration commands."""
pass
@hotreload_group.command(name="notifychannel")
async def hotreload_notifychannel(self, ctx: commands.Context, channel: discord.TextChannel) -> None:
@ -155,7 +155,6 @@ class HotReloadHandler(RegexMatchingEventHandler):
loop=self.cog.bot.loop,
)
# pylint: disable=protected-access
async def reload_cogs(self, cog_names: Sequence[str], paths: Sequence[Path]) -> None:
"""Reload modified cogs."""
if not self.compile_modified_files(cog_names, paths):

View file

@ -2,29 +2,28 @@ from redbot.core import Config
config: Config = Config.get_conf(None, identifier=457581387213637448123567, cog_name="Pterodactyl", force_registration=True)
def register_config(config_obj: Config) -> None:
config_obj.register_global(
base_url=None,
server_id=None,
console_channel=None,
console_commands_enabled=False,
current_status="",
current_status='',
chat_regex=r"^\[\d{2}:\d{2}:\d{2}\sINFO\]: (?!\[(?:Server|Rcon)\])(?:<|\[)(\w+)(?:>|\]) (.*)",
server_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]:(?: \[Not Secure\])? \[(?:Server|Rcon)\] (.*)",
join_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: ([^<\n]+) joined the game$",
leave_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: ([^<\n]+) left the game$",
achievement_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: (.*) has (made the advancement|completed the challenge) \[(.*)\]$",
chat_command='tellraw @a ["",{"text":".$N ","color":".$C","insertion":"<@.$I>","hoverEvent":{"action":"show_text","contents":"Shift click to mention this user inside Discord"}},{"text":"(DISCORD):","color":"blue","clickEvent":{"action":"open_url","value":".$V"},"hoverEvent":{"action":"show_text","contents":"Click to join the Discord Server"}},{"text":" .$M","color":"white"}]', # noqa: E501
topic="Server IP: .$H\nServer Players: .$P/.$M",
chat_command='tellraw @a ["",{"text":".$N ","color":".$C","insertion":"<@.$I>","hoverEvent":{"action":"show_text","contents":"Shift click to mention this user inside Discord"}},{"text":"(DISCORD):","color":"blue","clickEvent":{"action":"open_url","value":".$V"},"hoverEvent":{"action":"show_text","contents":"Click to join the Discord Server"}},{"text":" .$M","color":"white"}]', # noqa: E501
topic='Server IP: .$H\nServer Players: .$P/.$M',
topic_hostname=None,
topic_port=25565,
api_endpoint="minecraft",
chat_channel=None,
startup_msg="Server started!",
shutdown_msg="Server stopped!",
join_msg="Welcome to the server! 👋",
leave_msg="Goodbye! 👋",
startup_msg='Server started!',
shutdown_msg='Server stopped!',
join_msg='Welcome to the server! 👋',
leave_msg='Goodbye! 👋',
mask_ip=True,
invite=None,
regex_blacklist={},