Skip to content

Commit

Permalink
Start rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
hypergonial committed Jan 29, 2024
1 parent 3343a6b commit 1daaff3
Show file tree
Hide file tree
Showing 27 changed files with 1,218 additions and 1,113 deletions.
24 changes: 13 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[tool.ruff]
exclude = ["examples", "docs", "build"]
select = [
"E",
"F",
"I",
"TCH",
"N",
"E",
"F",
"I",
"TCH",
"N",
"D2",
"D3",
"D415",
Expand All @@ -28,12 +28,13 @@ ignore_errors = true # I use pyright only because mypy dumb
[tool.pyright]
pythonVersion = "3.11"
typeCheckingMode = "basic"
reportPrivateUsage = "none"

[tool.poetry]
name = "snedbot"
version = "0.1.0" # I do not actually update this, lol
version = "0.1.0" # I do not actually update this, lol
description = "Your friendly neighbourhood multi-purpose Discord bot."
authors = ["hypergonial <46067571+hypergonial@users.noreply.github.com>"]
authors = ["hypergonial <git@hypergonial.com>"]
license = "GNU GPL-v3"

[tool.poetry.dependencies]
Expand All @@ -43,13 +44,14 @@ psutil = "^5.9.6"
Pillow = "^10.2.0"
asyncpg = "^0.28.0"
Levenshtein = "^0.23.0"
uvloop = {version = "==0.18.0", platform="linux"}
uvloop = { version = "==0.18.0", platform = "linux" }
aiodns = "~=3.1.1"
Brotli = "~=1.0"
ciso8601 = "~=2.3"
kosu = {git = "https://github.com/hypergonial/kosu.git"}
hikari-lightbulb = "~=2.3.5"
hikari-miru = "~=3.3.1"
kosu = { git = "https://github.com/hypergonial/kosu.git" }
hikari-arc = "~=1.2.0"
hikari-toolbox = "~=0.1.6"
hikari-miru = "~=4.0.0"

[tool.poetry.dev-dependencies]
nox = "^2023.4.22"
Expand Down
6 changes: 3 additions & 3 deletions src/db/migrations/7.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _parse_note(db: Database, user_id: int, guild_id: int, note: str) -> Journal
logger.warning(f"Invalid note format:\n{note}")
return

users = db.app.cache.get_users_view()
users = db.client.cache.get_users_view()
user: hikari.User | None = (
lightbulb.utils.find(users.values(), lambda u: str(u) == match.group("username"))
if match.group("username") != "Unknown"
Expand All @@ -67,7 +67,7 @@ def _parse_note(db: Database, user_id: int, guild_id: int, note: str) -> Journal

async def _migrate_notes(db: Database) -> None:
logger.warning("Waiting for cache availability to start journal entry migration...")
await db.app.wait_until_started()
await db.client.wait_until_started()

logger.warning("Migrating journal entries...")
records = await db.fetch("SELECT * FROM users")
Expand All @@ -92,4 +92,4 @@ async def _migrate_notes(db: Database) -> None:

async def run(db: Database) -> None:
# Defer execution to after startup, don't block
db._app.create_task(_migrate_notes(db))
db._client.create_task(_migrate_notes(db))
32 changes: 15 additions & 17 deletions src/extensions/annoverse.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import arc
import hikari
import lightbulb
import toolbox

import src.etc.const as const
from src.config import Config
from src.models.bot import SnedBot
from src.models.context import SnedContext
from src.models.plugin import SnedPlugin
from src.models.client import SnedClient, SnedContext, SnedPlugin
from src.utils import helpers

annoverse = SnedPlugin("Annoverse")
annoverse.default_enabled_guilds = Config().DEBUG_GUILDS or (372128553031958529,)
plugin = SnedPlugin("Annoverse", default_enabled_guilds=Config().DEBUG_GUILDS or (372128553031958529,))

QUESTIONS_CHANNEL_ID = 955463477760229397
OUTPUT_CHANNEL_ID = 955463511767654450

question_counters: dict[hikari.Snowflake, int] = {}


@annoverse.command
@lightbulb.option("question", "The question you want to ask!")
@lightbulb.command("ask", "Ask a question on the roundtable!", pass_options=True)
@lightbulb.implements(lightbulb.SlashCommand)
async def ask_cmd(ctx: SnedContext, question: str) -> None:
@plugin.include
@arc.slash_command("ask", "Ask a question on the roundtable!")
async def ask_cmd(ctx: SnedContext, question: arc.Option[str, arc.StrParams("The question you want to ask!")]) -> None:
assert ctx.member is not None and ctx.interaction is not None

if ctx.channel_id != QUESTIONS_CHANNEL_ID:
Expand All @@ -45,7 +41,7 @@ async def ask_cmd(ctx: SnedContext, question: str) -> None:
question_counters.get(ctx.author.id)
and question_counters[ctx.author.id] >= 3
and not helpers.includes_permissions(
lightbulb.utils.permissions_for(ctx.member), hikari.Permissions.MANAGE_MESSAGES
toolbox.calculate_permissions(ctx.member), hikari.Permissions.MANAGE_MESSAGES
)
):
if ctx.interaction.locale == "de":
Expand All @@ -64,7 +60,7 @@ async def ask_cmd(ctx: SnedContext, question: str) -> None:
return

await ctx.respond(hikari.ResponseType.DEFERRED_MESSAGE_CREATE)
await ctx.app.rest.create_message(OUTPUT_CHANNEL_ID, f"{ctx.member.mention} **asks:** {question[:500]}")
await ctx.client.rest.create_message(OUTPUT_CHANNEL_ID, f"{ctx.member.mention} **asks:** {question[:500]}")
if not question_counters.get(ctx.author.id):
question_counters[ctx.author.id] = 0
question_counters[ctx.author.id] += 1
Expand All @@ -84,12 +80,14 @@ async def ask_cmd(ctx: SnedContext, question: str) -> None:
await ctx.respond(embed=embed)


def load(bot: SnedBot) -> None:
bot.add_plugin(annoverse)
@arc.loader
def load(client: SnedClient) -> None:
client.add_plugin(plugin)


def unload(bot: SnedBot) -> None:
bot.remove_plugin(annoverse)
@arc.unloader
def unload(client: SnedClient) -> None:
client.remove_plugin(plugin)


# Copyright (C) 2022-present hypergonial
Expand Down
76 changes: 39 additions & 37 deletions src/extensions/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
import re
import typing as t

import arc
import hikari
import kosu
import lightbulb

import src.utils as utils
from src.etc import const
from src.etc.settings_static import default_automod_policies, notices
from src.models.bot import SnedBot
from src.models.client import SnedClient, SnedPlugin
from src.models.events import AutoModMessageFlagEvent
from src.models.plugin import SnedPlugin
from src.utils import helpers
from src.utils.ratelimiter import MemberBucket

Expand All @@ -34,8 +33,7 @@

logger = logging.getLogger(__name__)

automod = SnedPlugin("Auto-Moderation", include_datastore=True)
automod.d.actions = lightbulb.utils.DataStore()
plugin = SnedPlugin("Auto-Moderation")


class AutomodActionType(enum.Enum):
Expand Down Expand Up @@ -79,7 +77,7 @@ async def get_policies(guild: hikari.SnowflakeishOr[hikari.Guild]) -> dict[str,
"""
guild_id = hikari.Snowflake(guild)

records = await automod.app.db_cache.get(table="mod_config", guild_id=guild_id)
records = await plugin.client.db_cache.get(table="mod_config", guild_id=guild_id)

policies = json.loads(records[0]["automod_policies"]) if records else default_automod_policies

Expand All @@ -102,9 +100,6 @@ async def get_policies(guild: hikari.SnowflakeishOr[hikari.Guild]) -> dict[str,
return policies


automod.d.actions.get_policies = get_policies


def can_automod_punish(me: hikari.Member, offender: hikari.Member) -> bool:
"""Determine if automod can punish a member.
This checks all required permissions and if the member is a cool person or not.
Expand All @@ -130,7 +125,7 @@ def can_automod_punish(me: hikari.Member, offender: hikari.Member) -> bool:

assert offender.guild_id is not None

if offender.id in automod.app.owner_ids:
if offender.id in plugin.client.owner_ids:
return False # Hyper is always a good person

if not helpers.can_harm(me, offender, permission=required_perms):
Expand Down Expand Up @@ -171,8 +166,8 @@ async def punish(
assert message.guild_id is not None
assert message.author is not hikari.UNDEFINED

offender = offender or automod.app.cache.get_member(message.guild_id, message.author.id)
me = automod.app.cache.get_member(message.guild_id, automod.app.user_id)
offender = offender or plugin.client.cache.get_member(message.guild_id, message.author.id)
me = plugin.client.cache.get_member(message.guild_id, plugin.client.user_id)
assert offender is not None and me is not None

if not skip_check and not can_automod_punish(me, offender):
Expand Down Expand Up @@ -218,9 +213,13 @@ async def punish(
await helpers.maybe_delete(message)

if state == AutoModState.FLAG.value:
return await automod.app.dispatch(
return await plugin.client.app.dispatch(
AutoModMessageFlagEvent(
automod.app, message, offender, message.guild_id, f"Message flagged by auto-moderator for {reason}."
plugin.client.app,
message,
offender,
message.guild_id,
f"Message flagged by auto-moderator for {reason}.",
)
)

Expand All @@ -234,14 +233,18 @@ async def punish(
),
user_mentions=True,
)
return await automod.app.dispatch(
return await plugin.client.app.dispatch(
AutoModMessageFlagEvent(
automod.app, message, offender, message.guild_id, f"Message flagged by auto-moderator for {reason}."
plugin.client.app,
message,
offender,
message.guild_id,
f"Message flagged by auto-moderator for {reason}.",
)
)

if state == AutoModState.WARN.value:
embed = await automod.app.mod.warn(offender, me, f"Warned by auto-moderator for {reason}.")
embed = await plugin.client.mod.warn(offender, me, f"Warned by auto-moderator for {reason}.")
await message.respond(embed=embed)
return

Expand All @@ -258,9 +261,9 @@ async def punish(
),
user_mentions=True,
)
return await automod.app.dispatch(
return await plugin.client.app.dispatch(
AutoModMessageFlagEvent(
automod.app,
plugin.client.app,
message,
offender,
message.guild_id,
Expand All @@ -269,7 +272,7 @@ async def punish(
)

elif ESCALATE_PREWARN_RATELIMITER.is_rate_limited(message):
embed = await automod.app.mod.warn(
embed = await plugin.client.mod.warn(
offender,
me,
f"Warned by auto-moderator for previous offenses ({action.name}).",
Expand All @@ -290,7 +293,7 @@ async def punish(
)

elif state == AutoModState.TIMEOUT.value:
embed = await automod.app.mod.timeout(
embed = await plugin.client.mod.timeout(
offender,
me,
helpers.utcnow() + datetime.timedelta(minutes=temp_dur),
Expand All @@ -300,19 +303,19 @@ async def punish(
return

elif state == AutoModState.KICK.value:
embed = await automod.app.mod.kick(offender, me, reason=f"Kicked by auto-moderator for {reason}.")
embed = await plugin.client.mod.kick(offender, me, reason=f"Kicked by auto-moderator for {reason}.")
await message.respond(embed=embed)
return

elif state == AutoModState.SOFTBAN.value:
embed = await automod.app.mod.ban(
embed = await plugin.client.mod.ban(
offender, me, soft=True, reason=f"Soft-banned by auto-moderator for {reason}.", days_to_delete=1
)
await message.respond(embed=embed)
return

elif state == AutoModState.TEMPBAN.value:
embed = await automod.app.mod.ban(
embed = await plugin.client.mod.ban(
offender,
me,
duration=helpers.utcnow() + datetime.timedelta(minutes=temp_dur),
Expand All @@ -322,7 +325,7 @@ async def punish(
return

elif state == AutoModState.PERMABAN.value:
embed = await automod.app.mod.ban(offender, me, reason=f"Permanently banned by auto-moderator for {reason}.")
embed = await plugin.client.mod.ban(offender, me, reason=f"Permanently banned by auto-moderator for {reason}.")
await message.respond(embed=embed)
return

Expand Down Expand Up @@ -566,7 +569,7 @@ async def detect_perspective(message: hikari.PartialMessage, policies: dict[str,
assert message.guild_id and message.member

if policies["perspective"]["state"] != AutoModState.DISABLED.value:
me = automod.app.cache.get_member(message.guild_id, automod.app.user_id)
me = plugin.client.cache.get_member(message.guild_id, plugin.client.user_id)
assert me is not None

# This is a pretty expensive check so we'll only do it if we have to
Expand All @@ -588,7 +591,7 @@ async def detect_perspective(message: hikari.PartialMessage, policies: dict[str,
return True

try:
resp: kosu.AnalysisResponse = await automod.app.perspective.analyze(message.content, persp_attribs)
resp: kosu.AnalysisResponse = await plugin.client.perspective.analyze(message.content, persp_attribs)
except kosu.PerspectiveException as e:
logger.debug(f"Perspective failed to analyze a message: {e}")
else:
Expand All @@ -607,19 +610,16 @@ async def detect_perspective(message: hikari.PartialMessage, policies: dict[str,
return True


@automod.listener(hikari.GuildMessageCreateEvent, bind=True)
@automod.listener(hikari.GuildMessageUpdateEvent, bind=True)
async def scan_messages(
plugin: SnedPlugin, event: hikari.GuildMessageCreateEvent | hikari.GuildMessageUpdateEvent
) -> None:
@plugin.listen()
async def scan_messages(event: hikari.GuildMessageCreateEvent | hikari.GuildMessageUpdateEvent) -> None:
"""Scan messages for all possible offences."""
message = event.message

if not message.author:
# Probably a partial update, ignore it
return

if not plugin.app.is_started or not plugin.app.db_cache.is_ready:
if not plugin.client.is_started or not plugin.client.db_cache.is_ready:
return

if message.guild_id is None:
Expand Down Expand Up @@ -655,12 +655,14 @@ async def scan_messages(
)


def load(bot: SnedBot) -> None:
bot.add_plugin(automod)
@arc.loader
def load(client: SnedClient) -> None:
client.add_plugin(plugin)


def unload(bot: SnedBot) -> None:
bot.remove_plugin(automod)
@arc.unloader
def unload(client: SnedClient) -> None:
client.remove_plugin(plugin)


# Copyright (C) 2022-present hypergonial
Expand Down
Loading

0 comments on commit 1daaff3

Please sign in to comment.