From e19b7429b2c50c850f570c02945296ddc1dc8881 Mon Sep 17 00:00:00 2001 From: thanos Date: Sat, 17 May 2025 19:42:06 -0400 Subject: [PATCH 01/17] refactor(database): Initial Guild and GuildConfig SQLModel schemas added, started removal of prisma schemas --- .../migrations/20250405050252_/migration.sql | 247 ++++++++++++++++++ prisma/migrations/migration_lock.toml | 3 + prisma/schema/guild/config.prisma | 28 -- pyproject.toml | 1 + tux/database/schemas/__init__.py | 0 tux/database/schemas/guild.py | 92 +++++++ .../database/schemas}/guild/guild.prisma | 0 .../database/schemas}/guild/levels.prisma | 0 .../database/schemas}/guild/starboard.prisma | 0 9 files changed, 343 insertions(+), 28 deletions(-) create mode 100644 prisma/migrations/20250405050252_/migration.sql create mode 100644 prisma/migrations/migration_lock.toml delete mode 100644 prisma/schema/guild/config.prisma create mode 100644 tux/database/schemas/__init__.py create mode 100644 tux/database/schemas/guild.py rename {prisma/schema => tux/database/schemas}/guild/guild.prisma (100%) rename {prisma/schema => tux/database/schemas}/guild/levels.prisma (100%) rename {prisma/schema => tux/database/schemas}/guild/starboard.prisma (100%) diff --git a/prisma/migrations/20250405050252_/migration.sql b/prisma/migrations/20250405050252_/migration.sql new file mode 100644 index 00000000..8ea45a06 --- /dev/null +++ b/prisma/migrations/20250405050252_/migration.sql @@ -0,0 +1,247 @@ +-- CreateEnum +CREATE TYPE "CaseType" AS ENUM ('BAN', 'UNBAN', 'HACKBAN', 'TEMPBAN', 'KICK', 'SNIPPETBAN', 'TIMEOUT', 'UNTIMEOUT', 'WARN', 'JAIL', 'UNJAIL', 'SNIPPETUNBAN', 'UNTEMPBAN', 'POLLBAN', 'POLLUNBAN'); + +-- CreateTable +CREATE TABLE "AFKModel" ( + "member_id" BIGINT NOT NULL, + "nickname" TEXT NOT NULL, + "reason" TEXT NOT NULL, + "since" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "guild_id" BIGINT NOT NULL, + "perm_afk" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "AFKModel_pkey" PRIMARY KEY ("member_id") +); + +-- CreateTable +CREATE TABLE "Note" ( + "note_id" BIGSERIAL NOT NULL, + "note_content" TEXT NOT NULL, + "note_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "note_moderator_id" BIGINT NOT NULL, + "note_user_id" BIGINT NOT NULL, + "note_number" BIGINT, + "guild_id" BIGINT NOT NULL, + + CONSTRAINT "Note_pkey" PRIMARY KEY ("note_id") +); + +-- CreateTable +CREATE TABLE "Case" ( + "case_id" BIGSERIAL NOT NULL, + "case_status" BOOLEAN DEFAULT true, + "case_type" "CaseType" NOT NULL, + "case_reason" TEXT NOT NULL, + "case_moderator_id" BIGINT NOT NULL, + "case_user_id" BIGINT NOT NULL, + "case_user_roles" BIGINT[] DEFAULT ARRAY[]::BIGINT[], + "case_number" BIGINT, + "case_created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "case_expires_at" TIMESTAMP(3), + "case_tempban_expired" BOOLEAN DEFAULT false, + "guild_id" BIGINT NOT NULL, + + CONSTRAINT "Case_pkey" PRIMARY KEY ("case_id") +); + +-- CreateTable +CREATE TABLE "Reminder" ( + "reminder_id" BIGSERIAL NOT NULL, + "reminder_content" TEXT NOT NULL, + "reminder_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "reminder_expires_at" TIMESTAMP(3) NOT NULL, + "reminder_channel_id" BIGINT NOT NULL, + "reminder_user_id" BIGINT NOT NULL, + "reminder_sent" BOOLEAN NOT NULL DEFAULT false, + "guild_id" BIGINT NOT NULL, + + CONSTRAINT "Reminder_pkey" PRIMARY KEY ("reminder_id") +); + +-- CreateTable +CREATE TABLE "Snippet" ( + "snippet_id" BIGSERIAL NOT NULL, + "snippet_name" TEXT NOT NULL, + "snippet_content" TEXT NOT NULL, + "snippet_user_id" BIGINT NOT NULL, + "snippet_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "guild_id" BIGINT NOT NULL, + "uses" BIGINT NOT NULL DEFAULT 0, + "locked" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "Snippet_pkey" PRIMARY KEY ("snippet_id") +); + +-- CreateTable +CREATE TABLE "GuildConfig" ( + "prefix" TEXT, + "mod_log_id" BIGINT, + "audit_log_id" BIGINT, + "join_log_id" BIGINT, + "private_log_id" BIGINT, + "report_log_id" BIGINT, + "dev_log_id" BIGINT, + "jail_channel_id" BIGINT, + "general_channel_id" BIGINT, + "starboard_channel_id" BIGINT, + "perm_level_0_role_id" BIGINT, + "perm_level_1_role_id" BIGINT, + "perm_level_2_role_id" BIGINT, + "perm_level_3_role_id" BIGINT, + "perm_level_4_role_id" BIGINT, + "perm_level_5_role_id" BIGINT, + "perm_level_6_role_id" BIGINT, + "perm_level_7_role_id" BIGINT, + "base_staff_role_id" BIGINT, + "base_member_role_id" BIGINT, + "jail_role_id" BIGINT, + "quarantine_role_id" BIGINT, + "guild_id" BIGINT NOT NULL, + + CONSTRAINT "GuildConfig_pkey" PRIMARY KEY ("guild_id") +); + +-- CreateTable +CREATE TABLE "Guild" ( + "guild_id" BIGINT NOT NULL, + "guild_joined_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "case_count" BIGINT NOT NULL DEFAULT 0, + + CONSTRAINT "Guild_pkey" PRIMARY KEY ("guild_id") +); + +-- CreateTable +CREATE TABLE "Levels" ( + "member_id" BIGINT NOT NULL, + "xp" DOUBLE PRECISION NOT NULL DEFAULT 0, + "level" BIGINT NOT NULL DEFAULT 0, + "blacklisted" BOOLEAN NOT NULL DEFAULT false, + "last_message" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "guild_id" BIGINT NOT NULL, + + CONSTRAINT "Levels_pkey" PRIMARY KEY ("member_id","guild_id") +); + +-- CreateTable +CREATE TABLE "Starboard" ( + "guild_id" BIGINT NOT NULL, + "starboard_channel_id" BIGINT NOT NULL, + "starboard_emoji" TEXT NOT NULL, + "starboard_threshold" INTEGER NOT NULL, + + CONSTRAINT "Starboard_pkey" PRIMARY KEY ("guild_id") +); + +-- CreateTable +CREATE TABLE "StarboardMessage" ( + "message_id" BIGINT NOT NULL, + "message_content" TEXT NOT NULL, + "message_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "message_expires_at" TIMESTAMP(3) NOT NULL, + "message_channel_id" BIGINT NOT NULL, + "message_user_id" BIGINT NOT NULL, + "message_guild_id" BIGINT NOT NULL, + "star_count" INTEGER NOT NULL DEFAULT 0, + "starboard_message_id" BIGINT NOT NULL, + + CONSTRAINT "StarboardMessage_pkey" PRIMARY KEY ("message_id") +); + +-- CreateIndex +CREATE INDEX "AFKModel_member_id_idx" ON "AFKModel"("member_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "AFKModel_member_id_guild_id_key" ON "AFKModel"("member_id", "guild_id"); + +-- CreateIndex +CREATE INDEX "Note_note_number_guild_id_idx" ON "Note"("note_number", "guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Note_note_number_guild_id_key" ON "Note"("note_number", "guild_id"); + +-- CreateIndex +CREATE INDEX "Case_case_number_guild_id_idx" ON "Case"("case_number", "guild_id"); + +-- CreateIndex +CREATE INDEX "Case_guild_id_case_user_id_idx" ON "Case"("guild_id", "case_user_id"); + +-- CreateIndex +CREATE INDEX "Case_guild_id_case_moderator_id_idx" ON "Case"("guild_id", "case_moderator_id"); + +-- CreateIndex +CREATE INDEX "Case_guild_id_case_type_idx" ON "Case"("guild_id", "case_type"); + +-- CreateIndex +CREATE INDEX "Case_case_type_case_expires_at_case_tempban_expired_idx" ON "Case"("case_type", "case_expires_at", "case_tempban_expired"); + +-- CreateIndex +CREATE INDEX "Case_case_created_at_idx" ON "Case"("case_created_at" DESC); + +-- CreateIndex +CREATE UNIQUE INDEX "Case_case_number_guild_id_key" ON "Case"("case_number", "guild_id"); + +-- CreateIndex +CREATE INDEX "Reminder_reminder_id_guild_id_idx" ON "Reminder"("reminder_id", "guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Reminder_reminder_id_guild_id_key" ON "Reminder"("reminder_id", "guild_id"); + +-- CreateIndex +CREATE INDEX "Snippet_snippet_name_guild_id_idx" ON "Snippet"("snippet_name", "guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Snippet_snippet_name_guild_id_key" ON "Snippet"("snippet_name", "guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "GuildConfig_guild_id_key" ON "GuildConfig"("guild_id"); + +-- CreateIndex +CREATE INDEX "GuildConfig_guild_id_idx" ON "GuildConfig"("guild_id"); + +-- CreateIndex +CREATE INDEX "Guild_guild_id_idx" ON "Guild"("guild_id"); + +-- CreateIndex +CREATE INDEX "Levels_member_id_idx" ON "Levels"("member_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Levels_member_id_guild_id_key" ON "Levels"("member_id", "guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Starboard_guild_id_key" ON "Starboard"("guild_id"); + +-- CreateIndex +CREATE INDEX "Starboard_guild_id_idx" ON "Starboard"("guild_id"); + +-- CreateIndex +CREATE INDEX "StarboardMessage_message_id_message_guild_id_idx" ON "StarboardMessage"("message_id", "message_guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "StarboardMessage_message_id_message_guild_id_key" ON "StarboardMessage"("message_id", "message_guild_id"); + +-- AddForeignKey +ALTER TABLE "AFKModel" ADD CONSTRAINT "AFKModel_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Note" ADD CONSTRAINT "Note_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Case" ADD CONSTRAINT "Case_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Snippet" ADD CONSTRAINT "Snippet_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GuildConfig" ADD CONSTRAINT "GuildConfig_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Levels" ADD CONSTRAINT "Levels_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Starboard" ADD CONSTRAINT "Starboard_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "StarboardMessage" ADD CONSTRAINT "StarboardMessage_message_guild_id_fkey" FOREIGN KEY ("message_guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 00000000..fbffa92c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema/guild/config.prisma b/prisma/schema/guild/config.prisma deleted file mode 100644 index f6c6581b..00000000 --- a/prisma/schema/guild/config.prisma +++ /dev/null @@ -1,28 +0,0 @@ -model GuildConfig { - prefix String? - mod_log_id BigInt? - audit_log_id BigInt? - join_log_id BigInt? - private_log_id BigInt? - report_log_id BigInt? - dev_log_id BigInt? - jail_channel_id BigInt? - general_channel_id BigInt? - starboard_channel_id BigInt? - perm_level_0_role_id BigInt? - perm_level_1_role_id BigInt? - perm_level_2_role_id BigInt? - perm_level_3_role_id BigInt? - perm_level_4_role_id BigInt? - perm_level_5_role_id BigInt? - perm_level_6_role_id BigInt? - perm_level_7_role_id BigInt? - base_staff_role_id BigInt? - base_member_role_id BigInt? - jail_role_id BigInt? - quarantine_role_id BigInt? - guild_id BigInt @id @unique - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@index([guild_id]) -} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0ff12204..d842ddb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,7 @@ arrow = "^1.3.0" click = "^8.1.8" levenshtein = "^0.27.1" jinja2 = "^3.1.6" +sqlmodel = "^0.0.24" [tool.poetry.group.dev.dependencies] pre-commit = ">=4.0.0" diff --git a/tux/database/schemas/__init__.py b/tux/database/schemas/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tux/database/schemas/guild.py b/tux/database/schemas/guild.py new file mode 100644 index 00000000..70c38c27 --- /dev/null +++ b/tux/database/schemas/guild.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from datetime import UTC, datetime + +from sqlalchemy import BigInteger +from sqlmodel import Field, Relationship, SQLModel + + +# TODO: fill this in with relations to other schemas after they are written +class Guild(SQLModel, table=True): + guild_id: int = Field(primary_key=True, index=True, sa_column_kwargs={"type_": BigInteger}) + guild_joined_at: datetime | None = Field(default_factory=lambda: datetime.now(UTC)) + config: GuildConfig = Relationship(back_populates="guild") + case_count: int = Field(default=0) + + +class GuildConfig(SQLModel, table=True): + guild_id: int = Field(primary_key=True, unique=True, sa_column_kwargs={"type_": BigInteger}) + prefix: str | None = Field(default=None) + mod_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + audit_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + join_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + private_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + report_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + dev_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + jail_channel_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + general_channel_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + starboard_channel_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_0_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_1_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_2_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_3_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_4_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_5_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_6_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + perm_level_7_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + base_staff_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + base_member_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + jail_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + quarantine_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + + guild: Guild = Relationship(back_populates="config") + + +""" old prisma schemas, remove when no longer needed. +model Guild { + guild_id BigInt @id + guild_joined_at DateTime? @default(now()) + cases Case[] + snippets Snippet[] + notes Note[] + reminders Reminder[] + guild_config GuildConfig[] + AFK AFKModel[] + Starboard Starboard? + StarboardMessage StarboardMessage[] + case_count BigInt @default(0) + levels Levels[] + + @@index([guild_id]) + +model GuildConfig { + prefix String? + mod_log_id BigInt? + audit_log_id BigInt? + join_log_id BigInt? + private_log_id BigInt? + report_log_id BigInt? + dev_log_id BigInt? + jail_channel_id BigInt? + general_channel_id BigInt? + starboard_channel_id BigInt? + perm_level_0_role_id BigInt? + perm_level_1_role_id BigInt? + perm_level_2_role_id BigInt? + perm_level_3_role_id BigInt? + perm_level_4_role_id BigInt? + perm_level_5_role_id BigInt? + perm_level_6_role_id BigInt? + perm_level_7_role_id BigInt? + base_staff_role_id BigInt? + base_member_role_id BigInt? + jail_role_id BigInt? + quarantine_role_id BigInt? + guild_id BigInt @id @unique + guild Guild @relation(fields: [guild_id], references: [guild_id]) + + @@index([guild_id]) +} + +} +""" diff --git a/prisma/schema/guild/guild.prisma b/tux/database/schemas/guild/guild.prisma similarity index 100% rename from prisma/schema/guild/guild.prisma rename to tux/database/schemas/guild/guild.prisma diff --git a/prisma/schema/guild/levels.prisma b/tux/database/schemas/guild/levels.prisma similarity index 100% rename from prisma/schema/guild/levels.prisma rename to tux/database/schemas/guild/levels.prisma diff --git a/prisma/schema/guild/starboard.prisma b/tux/database/schemas/guild/starboard.prisma similarity index 100% rename from prisma/schema/guild/starboard.prisma rename to tux/database/schemas/guild/starboard.prisma From 57b9854c9bdf3f924c6d7a1b2c0f00468657c0d5 Mon Sep 17 00:00:00 2001 From: thanos Date: Sat, 17 May 2025 20:15:19 -0400 Subject: [PATCH 02/17] refactor(database): improved readability of new SQLModel Schemas --- tux/database/schemas/guild.py | 54 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/tux/database/schemas/guild.py b/tux/database/schemas/guild.py index 70c38c27..dd4a9bc9 100644 --- a/tux/database/schemas/guild.py +++ b/tux/database/schemas/guild.py @@ -2,42 +2,46 @@ from datetime import UTC, datetime -from sqlalchemy import BigInteger +from sqlalchemy import BigInteger, Column from sqlmodel import Field, Relationship, SQLModel # TODO: fill this in with relations to other schemas after they are written class Guild(SQLModel, table=True): - guild_id: int = Field(primary_key=True, index=True, sa_column_kwargs={"type_": BigInteger}) - guild_joined_at: datetime | None = Field(default_factory=lambda: datetime.now(UTC)) + """Represents a guild and associated metadata""" + + guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + guild_joined_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) config: GuildConfig = Relationship(back_populates="guild") case_count: int = Field(default=0) class GuildConfig(SQLModel, table=True): - guild_id: int = Field(primary_key=True, unique=True, sa_column_kwargs={"type_": BigInteger}) + """Configuration settings associated with a guild""" + + guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) prefix: str | None = Field(default=None) - mod_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - audit_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - join_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - private_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - report_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - dev_log_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - jail_channel_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - general_channel_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - starboard_channel_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_0_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_1_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_2_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_3_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_4_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_5_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_6_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - perm_level_7_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - base_staff_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - base_member_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - jail_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) - quarantine_role_id: int | None = Field(default=None, sa_column_kwargs={"type_": BigInteger}) + mod_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + audit_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + join_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + private_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + report_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + dev_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + jail_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + general_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + starboard_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_0_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_1_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_2_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_3_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_4_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_5_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_6_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_7_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + base_staff_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + base_member_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + jail_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + quarantine_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) guild: Guild = Relationship(back_populates="config") From 4f69fa495a8ca953a71aa95e82a1cb6f079f15a5 Mon Sep 17 00:00:00 2001 From: thanos Date: Sun, 18 May 2025 16:05:43 -0400 Subject: [PATCH 03/17] feat(database): finished writing new guild schemas --- tux/database/schemas/guild.py | 81 +++++++++++++-------- tux/database/schemas/guild/guild.prisma | 16 ---- tux/database/schemas/guild/levels.prisma | 13 ---- tux/database/schemas/guild/starboard.prisma | 25 ------- 4 files changed, 50 insertions(+), 85 deletions(-) delete mode 100644 tux/database/schemas/guild/guild.prisma delete mode 100644 tux/database/schemas/guild/levels.prisma delete mode 100644 tux/database/schemas/guild/starboard.prisma diff --git a/tux/database/schemas/guild.py b/tux/database/schemas/guild.py index dd4a9bc9..e554277c 100644 --- a/tux/database/schemas/guild.py +++ b/tux/database/schemas/guild.py @@ -1,18 +1,21 @@ from __future__ import annotations from datetime import UTC, datetime +from typing import Any -from sqlalchemy import BigInteger, Column +from sqlalchemy import BigInteger, Column, Index, UniqueConstraint from sqlmodel import Field, Relationship, SQLModel -# TODO: fill this in with relations to other schemas after they are written class Guild(SQLModel, table=True): """Represents a guild and associated metadata""" guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) guild_joined_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) config: GuildConfig = Relationship(back_populates="guild") + starboards: list[Starboard] | None = Relationship(back_populates="guild") + levels: list[Levels] | None = Relationship(back_populates="guild") + starboard_messages: list[StarboardMessage] | None = Relationship(back_populates="guild") case_count: int = Field(default=0) @@ -46,6 +49,51 @@ class GuildConfig(SQLModel, table=True): guild: Guild = Relationship(back_populates="config") +class Levels(SQLModel, table=True): + """Level information for a guild member""" + + member_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + xp: float = Field(default=0) + level: int = Field(default=0, sa_column=Column(BigInteger)) + blacklisted: bool = Field(default=False) + last_message: datetime = Field(default_factory=lambda: datetime.now(UTC)) + guild_id: int = Field(foreign_key="guild.guild_id", primary_key=True, sa_column=Column(BigInteger)) + + guild: Guild = Relationship(back_populates="levels") + + +class Starboard(SQLModel, table=True): + """Describes a starboard object for a guild""" + + guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + starboard_channel_id: int = Field(sa_column=Column(BigInteger)) + starboard_emoji: str = Field(nullable=False) + starboard_threshold: int = Field(default=5, nullable=False) + + guild: Guild = Relationship(back_populates="starboards") + + +class StarboardMessage(SQLModel, table=True): + """Describes a starboarded message""" + + message_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + message_content: str = Field(nullable=False) + message_created_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) + message_expires_at: datetime + message_channel_id: int = Field(sa_column=Column(BigInteger)) + message_user_id: int = Field(sa_column=Column(BigInteger)) + message_guild_id: int = Field(sa_column=Column(BigInteger)) + star_count: int = Field(default=0) + starboard_message_id: int = Field(nullable=False, sa_column=Column(BigInteger)) + + guild: Guild = Relationship(back_populates="starboard_messages") + + __table_args__: Any = ( + UniqueConstraint("message_id", "message_guild_id"), + Index("idx_message_id_guild_id", "message_id", "message_guild_id"), + ) + + """ old prisma schemas, remove when no longer needed. model Guild { guild_id BigInt @id @@ -63,34 +111,5 @@ class GuildConfig(SQLModel, table=True): @@index([guild_id]) -model GuildConfig { - prefix String? - mod_log_id BigInt? - audit_log_id BigInt? - join_log_id BigInt? - private_log_id BigInt? - report_log_id BigInt? - dev_log_id BigInt? - jail_channel_id BigInt? - general_channel_id BigInt? - starboard_channel_id BigInt? - perm_level_0_role_id BigInt? - perm_level_1_role_id BigInt? - perm_level_2_role_id BigInt? - perm_level_3_role_id BigInt? - perm_level_4_role_id BigInt? - perm_level_5_role_id BigInt? - perm_level_6_role_id BigInt? - perm_level_7_role_id BigInt? - base_staff_role_id BigInt? - base_member_role_id BigInt? - jail_role_id BigInt? - quarantine_role_id BigInt? - guild_id BigInt @id @unique - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@index([guild_id]) -} - } """ diff --git a/tux/database/schemas/guild/guild.prisma b/tux/database/schemas/guild/guild.prisma deleted file mode 100644 index cc6f8786..00000000 --- a/tux/database/schemas/guild/guild.prisma +++ /dev/null @@ -1,16 +0,0 @@ -model Guild { - guild_id BigInt @id - guild_joined_at DateTime? @default(now()) - cases Case[] - snippets Snippet[] - notes Note[] - reminders Reminder[] - guild_config GuildConfig[] - AFK AFKModel[] - Starboard Starboard? - StarboardMessage StarboardMessage[] - case_count BigInt @default(0) - levels Levels[] - - @@index([guild_id]) -} \ No newline at end of file diff --git a/tux/database/schemas/guild/levels.prisma b/tux/database/schemas/guild/levels.prisma deleted file mode 100644 index ed0a79f0..00000000 --- a/tux/database/schemas/guild/levels.prisma +++ /dev/null @@ -1,13 +0,0 @@ -model Levels { - member_id BigInt - xp Float @default(0) - level BigInt @default(0) - blacklisted Boolean @default(false) - last_message DateTime @default(now()) - guild_id BigInt - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@id([member_id, guild_id]) - @@unique([member_id, guild_id]) - @@index([member_id]) -} \ No newline at end of file diff --git a/tux/database/schemas/guild/starboard.prisma b/tux/database/schemas/guild/starboard.prisma deleted file mode 100644 index 2665051b..00000000 --- a/tux/database/schemas/guild/starboard.prisma +++ /dev/null @@ -1,25 +0,0 @@ -model Starboard { - guild_id BigInt @id @unique - starboard_channel_id BigInt - starboard_emoji String - starboard_threshold Int - Guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@index([guild_id]) -} - -model StarboardMessage { - message_id BigInt @id - message_content String - message_created_at DateTime @default(now()) - message_expires_at DateTime - message_channel_id BigInt - message_user_id BigInt - message_guild_id BigInt - star_count Int @default(0) - starboard_message_id BigInt - Guild Guild @relation(fields: [message_guild_id], references: [guild_id]) - - @@unique([message_id, message_guild_id]) - @@index([message_id, message_guild_id]) -} \ No newline at end of file From 940574233b0c56fed8ebba9ab12a104a09cb557f Mon Sep 17 00:00:00 2001 From: thanos Date: Sun, 18 May 2025 20:46:40 -0400 Subject: [PATCH 04/17] feat(database): New SQLModel schemas completed and placed in tux/database/schemas.py --- prisma/schema/commands/afk.prisma | 14 -- prisma/schema/commands/moderation.prisma | 60 ------- prisma/schema/commands/reminder.prisma | 14 -- prisma/schema/commands/snippets.prisma | 15 -- tux/database/schemas.py | 212 +++++++++++++++++++++++ tux/database/schemas/__init__.py | 0 tux/database/schemas/guild.py | 115 ------------ 7 files changed, 212 insertions(+), 218 deletions(-) delete mode 100644 prisma/schema/commands/afk.prisma delete mode 100644 prisma/schema/commands/moderation.prisma delete mode 100644 prisma/schema/commands/reminder.prisma delete mode 100644 prisma/schema/commands/snippets.prisma create mode 100644 tux/database/schemas.py delete mode 100644 tux/database/schemas/__init__.py delete mode 100644 tux/database/schemas/guild.py diff --git a/prisma/schema/commands/afk.prisma b/prisma/schema/commands/afk.prisma deleted file mode 100644 index 02f1e2e3..00000000 --- a/prisma/schema/commands/afk.prisma +++ /dev/null @@ -1,14 +0,0 @@ -model AFKModel { - member_id BigInt @id - nickname String - reason String - since DateTime @default(now()) - until DateTime? - guild_id BigInt - enforced Boolean @default(false) - perm_afk Boolean @default(false) - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@unique([member_id, guild_id]) - @@index([member_id]) -} \ No newline at end of file diff --git a/prisma/schema/commands/moderation.prisma b/prisma/schema/commands/moderation.prisma deleted file mode 100644 index 0b65348d..00000000 --- a/prisma/schema/commands/moderation.prisma +++ /dev/null @@ -1,60 +0,0 @@ -model Note { - note_id BigInt @id @default(autoincrement()) - note_content String - note_created_at DateTime @default(now()) - note_moderator_id BigInt - note_user_id BigInt - note_number BigInt? - guild_id BigInt - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@unique([note_number, guild_id]) - @@index([note_number, guild_id]) -} - -model Case { - case_id BigInt @id @default(autoincrement()) - case_status Boolean? @default(true) - case_type CaseType - case_reason String - case_moderator_id BigInt - case_user_id BigInt - case_user_roles BigInt[] @default([]) - case_number BigInt? - case_created_at DateTime? @default(now()) - case_expires_at DateTime? - case_tempban_expired Boolean? @default(false) - guild_id BigInt - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@unique([case_number, guild_id]) - @@index([case_number, guild_id]) - - @@index([guild_id, case_user_id]) - - @@index([guild_id, case_moderator_id]) - - @@index([guild_id, case_type]) - - @@index([case_type, case_expires_at, case_tempban_expired]) - - @@index([case_created_at(sort: Desc)]) -} - -enum CaseType { - BAN - UNBAN - HACKBAN - TEMPBAN - KICK - SNIPPETBAN - TIMEOUT - UNTIMEOUT - WARN - JAIL - UNJAIL - SNIPPETUNBAN - UNTEMPBAN - POLLBAN - POLLUNBAN -} \ No newline at end of file diff --git a/prisma/schema/commands/reminder.prisma b/prisma/schema/commands/reminder.prisma deleted file mode 100644 index 218c536d..00000000 --- a/prisma/schema/commands/reminder.prisma +++ /dev/null @@ -1,14 +0,0 @@ -model Reminder { - reminder_id BigInt @id @default(autoincrement()) - reminder_content String - reminder_created_at DateTime @default(now()) - reminder_expires_at DateTime - reminder_channel_id BigInt - reminder_user_id BigInt - reminder_sent Boolean @default(false) - guild_id BigInt - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@unique([reminder_id, guild_id]) - @@index([reminder_id, guild_id]) -} \ No newline at end of file diff --git a/prisma/schema/commands/snippets.prisma b/prisma/schema/commands/snippets.prisma deleted file mode 100644 index 836ba58c..00000000 --- a/prisma/schema/commands/snippets.prisma +++ /dev/null @@ -1,15 +0,0 @@ -model Snippet { - snippet_id BigInt @id @default(autoincrement()) - snippet_name String - snippet_content String? // optional cause of snippet aliases - snippet_user_id BigInt - snippet_created_at DateTime @default(now()) - guild_id BigInt - uses BigInt @default(0) - locked Boolean @default(false) - alias String? // name of another snippet - guild Guild @relation(fields: [guild_id], references: [guild_id]) - - @@unique([snippet_name, guild_id]) - @@index([snippet_name, guild_id]) -} diff --git a/tux/database/schemas.py b/tux/database/schemas.py new file mode 100644 index 00000000..03d115af --- /dev/null +++ b/tux/database/schemas.py @@ -0,0 +1,212 @@ +from __future__ import annotations + +from datetime import UTC, datetime +from enum import IntEnum +from typing import Any + +from sqlalchemy import BigInteger, Column, Index, UniqueConstraint +from sqlmodel import Field, Relationship, SQLModel + + +class GuildConfig(SQLModel, table=True): + """Configuration settings associated with a guild""" + + guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + prefix: str | None = Field(default=None) + mod_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + audit_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + join_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + private_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + report_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + dev_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + jail_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + general_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + starboard_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_0_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_1_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_2_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_3_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_4_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_5_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_6_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + perm_level_7_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + base_staff_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + base_member_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + jail_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + quarantine_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) + + guild: Guild = Relationship(back_populates="config") + + +class Levels(SQLModel, table=True): + """Level information for a guild member""" + + member_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + xp: float = Field(default=0) + level: int = Field(default=0, sa_column=Column(BigInteger)) + blacklisted: bool = Field(default=False) + last_message: datetime = Field(default_factory=lambda: datetime.now(UTC)) + guild_id: int = Field(foreign_key="guild.guild_id", primary_key=True, sa_column=Column(BigInteger)) + + guild: Guild = Relationship(back_populates="levels") + + +class Starboard(SQLModel, table=True): + """Describes a starboard object for a guild""" + + guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + starboard_channel_id: int = Field(sa_column=Column(BigInteger)) + starboard_emoji: str = Field(nullable=False) + starboard_threshold: int = Field(default=5, nullable=False) + + guild: Guild = Relationship(back_populates="starboards") + + +class StarboardMessage(SQLModel, table=True): + """Describes a starboarded message""" + + message_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + message_content: str = Field(nullable=False) + message_created_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) + message_expires_at: datetime + message_channel_id: int = Field(sa_column=Column(BigInteger)) + message_user_id: int = Field(sa_column=Column(BigInteger)) + message_guild_id: int = Field(index=True, sa_column=Column(BigInteger)) + star_count: int = Field(default=0) + starboard_message_id: int = Field(nullable=False, sa_column=Column(BigInteger)) + + guild: Guild = Relationship(back_populates="starboard_messages") + + __table_args__: Any = (UniqueConstraint("message_id", "message_guild_id"),) + + +class AFKModel(SQLModel, table=True): + member_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + nickname: str + reason: str + since: datetime = Field(default_factory=datetime.now) + until: datetime | None = Field(default=None) + guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") + enforced: bool = Field(default=False) + perm_afk: bool = Field(default=False) + guild: Guild = Relationship(back_populates="afk_models") + + __table_args__ = (UniqueConstraint("member_id", "guild_id"),) + + +class Note(SQLModel, table=True): + note_id: int = Field(primary_key=True, sa_column=Column(BigInteger), auto_increment=True) + note_user_id: int = Field(sa_column=Column(BigInteger)) + note_moderator_id: int = Field(sa_column=Column(BigInteger)) + note_content: str + note_created_at: datetime = Field(default_factory=datetime.now) + note_number: int | None = Field(default=None) + guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") + guild: Guild | None = Relationship(back_populates="notes") + + __table_args__ = ( + UniqueConstraint("note_number", "guild_id"), + Index("index_note_number_guild_id", "note_number", "guild_id"), + ) + + +class CaseType(IntEnum): + """Enumerator used to describe what action a case was logged for""" + + OTHER = -1 + BAN = 0 + UNBAN = 1 + HACKBAN = 2 + TEMPBAN = 3 + KICK = 4 + SNIPPETBAN = 5 + TIMEOUT = 6 + UNTIMEOUT = 7 + WARN = 8 + JAIL = 9 + UNJAIL = 10 + SNIPPETUNBAN = 11 + UNTEMPBAN = 12 + POLLBAN = 13 + POLLUNBAN = 14 + + +class Case(SQLModel, table=True): + """Entry describing a moderation case""" + + case_id: int = Field(primary_key=True, sa_column=Column(BigInteger), auto_increment=True) + case_status: bool | None = Field(default=True) + case_type: CaseType = Field(default=CaseType.OTHER) + case_reason: str + case_moderator_id: int = Field(sa_column=Column(BigInteger)) + case_user_id: int = Field(sa_column=Column(BigInteger)) + case_user_roles: list[int] = Field(default_factory=list) + case_number: int | None = None + case_created_at: datetime | None = Field(default_factory=datetime.now) + case_expires_at: datetime | None = None + case_tempban_expired: bool | None = Field(default=False) + guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") + guild: Guild | None = Relationship(back_populates="cases") + + __table_args__ = ( + UniqueConstraint("case_number", "guild_id"), + Index("index_case_number_guild_id", "case_number", "guild_id"), + Index("index_guild_id_case_user_id", "guild_id", "case_user_id"), + Index("index_guild_id_case_moderator_id", "guild_id", "case_moderator_id"), + Index("index_guild_id_case_type", "guild_id", "case_type"), + Index( + "index_case_type_case_expires_at_tempban_expired", "case_type", "case_expires_at", "case_tempban_expired" + ), + Index("index_case_created_at_desc", "case_created_at", unique=False), + ) + + +class Reminder(SQLModel, table=True): + """Stores a reminder set by a user""" + + reminder_id: int = Field(primary_key=True, sa_column=Column(BigInteger), auto_increment=True) + reminder_content: str + reminder_created_at: datetime = Field(default_factory=datetime.now) + reminder_expires_at: datetime + reminder_channel_id: int = Field(sa_column=Column(BigInteger)) + reminder_user_id: int = Field(sa_column=Column(BigInteger)) + reminder_sent: bool = Field(default=False) + guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") + guild: Guild = Relationship(back_populates="reminders") + + +class Snippet(SQLModel, table=True): + """Stores a snippet, asmall unit of information that users can quickly retrieve from the bot""" + + snippet_id: int = Field(primary_key=True, sa_column=Column(BigInteger), auto_increment=True) + snippet_name: str + snippet_content: str | None = None + snippet_user_id: int = Field(sa_column=Column(BigInteger)) + snippet_created_at: datetime = Field(default_factory=datetime.now) + guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") + uses: int = Field(default=0) + locked: bool = Field(default=False) + alias: str | None = None + guild: Guild = Relationship(back_populates="snippets") + + __table_args__ = ( + UniqueConstraint("snippet_name", "guild_id"), + Index("index_snippet_name_guild_id", "snippet_name", "guild_id"), + ) + + +class Guild(SQLModel, table=True): + """Represents a guild and associated metadata""" + + guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) + guild_joined_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) + config: GuildConfig = Relationship(back_populates="guild") + starboards: list[Starboard] | None = Relationship(back_populates="guild") + levels: list[Levels] | None = Relationship(back_populates="guild") + starboard_messages: list[StarboardMessage] | None = Relationship(back_populates="guild") + afk_models: list[AFKModel] | None = Relationship(back_populates="guild") + cases: list[Case] | None = Relationship(back_populates="guild") + case_count: int = Field(default=0) + snippets: list[Snippet] = Relationship(back_populates="guild") + reminders: list[Reminder] = Relationship(back_populates="guild") + notes: list[Note] = Relationship(back_populates="guild") diff --git a/tux/database/schemas/__init__.py b/tux/database/schemas/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tux/database/schemas/guild.py b/tux/database/schemas/guild.py deleted file mode 100644 index e554277c..00000000 --- a/tux/database/schemas/guild.py +++ /dev/null @@ -1,115 +0,0 @@ -from __future__ import annotations - -from datetime import UTC, datetime -from typing import Any - -from sqlalchemy import BigInteger, Column, Index, UniqueConstraint -from sqlmodel import Field, Relationship, SQLModel - - -class Guild(SQLModel, table=True): - """Represents a guild and associated metadata""" - - guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) - guild_joined_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) - config: GuildConfig = Relationship(back_populates="guild") - starboards: list[Starboard] | None = Relationship(back_populates="guild") - levels: list[Levels] | None = Relationship(back_populates="guild") - starboard_messages: list[StarboardMessage] | None = Relationship(back_populates="guild") - case_count: int = Field(default=0) - - -class GuildConfig(SQLModel, table=True): - """Configuration settings associated with a guild""" - - guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) - prefix: str | None = Field(default=None) - mod_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - audit_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - join_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - private_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - report_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - dev_log_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - jail_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - general_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - starboard_channel_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_0_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_1_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_2_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_3_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_4_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_5_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_6_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - perm_level_7_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - base_staff_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - base_member_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - jail_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - quarantine_role_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - - guild: Guild = Relationship(back_populates="config") - - -class Levels(SQLModel, table=True): - """Level information for a guild member""" - - member_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) - xp: float = Field(default=0) - level: int = Field(default=0, sa_column=Column(BigInteger)) - blacklisted: bool = Field(default=False) - last_message: datetime = Field(default_factory=lambda: datetime.now(UTC)) - guild_id: int = Field(foreign_key="guild.guild_id", primary_key=True, sa_column=Column(BigInteger)) - - guild: Guild = Relationship(back_populates="levels") - - -class Starboard(SQLModel, table=True): - """Describes a starboard object for a guild""" - - guild_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) - starboard_channel_id: int = Field(sa_column=Column(BigInteger)) - starboard_emoji: str = Field(nullable=False) - starboard_threshold: int = Field(default=5, nullable=False) - - guild: Guild = Relationship(back_populates="starboards") - - -class StarboardMessage(SQLModel, table=True): - """Describes a starboarded message""" - - message_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) - message_content: str = Field(nullable=False) - message_created_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) - message_expires_at: datetime - message_channel_id: int = Field(sa_column=Column(BigInteger)) - message_user_id: int = Field(sa_column=Column(BigInteger)) - message_guild_id: int = Field(sa_column=Column(BigInteger)) - star_count: int = Field(default=0) - starboard_message_id: int = Field(nullable=False, sa_column=Column(BigInteger)) - - guild: Guild = Relationship(back_populates="starboard_messages") - - __table_args__: Any = ( - UniqueConstraint("message_id", "message_guild_id"), - Index("idx_message_id_guild_id", "message_id", "message_guild_id"), - ) - - -""" old prisma schemas, remove when no longer needed. -model Guild { - guild_id BigInt @id - guild_joined_at DateTime? @default(now()) - cases Case[] - snippets Snippet[] - notes Note[] - reminders Reminder[] - guild_config GuildConfig[] - AFK AFKModel[] - Starboard Starboard? - StarboardMessage StarboardMessage[] - case_count BigInt @default(0) - levels Levels[] - - @@index([guild_id]) - -} -""" From 3c5efb8690f02c73dcd36885350594c27b2b4645 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 00:46:57 +0000 Subject: [PATCH 05/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tux/database/schemas.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tux/database/schemas.py b/tux/database/schemas.py index 03d115af..4e139601 100644 --- a/tux/database/schemas.py +++ b/tux/database/schemas.py @@ -155,7 +155,10 @@ class Case(SQLModel, table=True): Index("index_guild_id_case_moderator_id", "guild_id", "case_moderator_id"), Index("index_guild_id_case_type", "guild_id", "case_type"), Index( - "index_case_type_case_expires_at_tempban_expired", "case_type", "case_expires_at", "case_tempban_expired" + "index_case_type_case_expires_at_tempban_expired", + "case_type", + "case_expires_at", + "case_tempban_expired", ), Index("index_case_created_at_desc", "case_created_at", unique=False), ) From eee9029ff47df9c3039b790c4315a46869c856d5 Mon Sep 17 00:00:00 2001 From: thanos Date: Mon, 19 May 2025 12:25:36 -0400 Subject: [PATCH 06/17] fix(database): ensure datetime.now calls return UTC --- tux/database/schemas.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tux/database/schemas.py b/tux/database/schemas.py index 4e139601..9501bedc 100644 --- a/tux/database/schemas.py +++ b/tux/database/schemas.py @@ -84,7 +84,7 @@ class AFKModel(SQLModel, table=True): member_id: int = Field(primary_key=True, sa_column=Column(BigInteger)) nickname: str reason: str - since: datetime = Field(default_factory=datetime.now) + since: datetime = Field(default_factory=lambda: datetime.now(UTC)) until: datetime | None = Field(default=None) guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") enforced: bool = Field(default=False) @@ -99,7 +99,7 @@ class Note(SQLModel, table=True): note_user_id: int = Field(sa_column=Column(BigInteger)) note_moderator_id: int = Field(sa_column=Column(BigInteger)) note_content: str - note_created_at: datetime = Field(default_factory=datetime.now) + note_created_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) note_number: int | None = Field(default=None) guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") guild: Guild | None = Relationship(back_populates="notes") @@ -142,7 +142,7 @@ class Case(SQLModel, table=True): case_user_id: int = Field(sa_column=Column(BigInteger)) case_user_roles: list[int] = Field(default_factory=list) case_number: int | None = None - case_created_at: datetime | None = Field(default_factory=datetime.now) + case_created_at: datetime | None = Field(default_factory=lambda: datetime.now(UTC)) case_expires_at: datetime | None = None case_tempban_expired: bool | None = Field(default=False) guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") @@ -169,7 +169,7 @@ class Reminder(SQLModel, table=True): reminder_id: int = Field(primary_key=True, sa_column=Column(BigInteger), auto_increment=True) reminder_content: str - reminder_created_at: datetime = Field(default_factory=datetime.now) + reminder_created_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) reminder_expires_at: datetime reminder_channel_id: int = Field(sa_column=Column(BigInteger)) reminder_user_id: int = Field(sa_column=Column(BigInteger)) @@ -185,7 +185,7 @@ class Snippet(SQLModel, table=True): snippet_name: str snippet_content: str | None = None snippet_user_id: int = Field(sa_column=Column(BigInteger)) - snippet_created_at: datetime = Field(default_factory=datetime.now) + snippet_created_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) guild_id: int = Field(sa_column=Column(BigInteger), foreign_key="guild.guild_id") uses: int = Field(default=0) locked: bool = Field(default=False) From f8048d736a8138cf1e7e4ce2cd23f7b78970bea6 Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:40:16 -0500 Subject: [PATCH 07/17] chore(poetry.lock): update lockfile --- poetry.lock | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index ec78402d..a6491f6d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "aiocache" @@ -1180,6 +1180,75 @@ gitdb = ">=4.0.1,<5" doc = ["sphinx (>=7.1.2,<7.2)", "sphinx-autodoc-typehints", "sphinx_rtd_theme"] test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3.8\"", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions ; python_version < \"3.11\""] +[[package]] +name = "greenlet" +version = "3.2.3" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" +files = [ + {file = "greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be"}, + {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:761917cac215c61e9dc7324b2606107b3b292a8349bdebb31503ab4de3f559ac"}, + {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a433dbc54e4a37e4fff90ef34f25a8c00aed99b06856f0119dcf09fbafa16392"}, + {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:72e77ed69312bab0434d7292316d5afd6896192ac4327d44f3d613ecb85b037c"}, + {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:68671180e3849b963649254a882cd544a3c75bfcd2c527346ad8bb53494444db"}, + {file = "greenlet-3.2.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49c8cfb18fb419b3d08e011228ef8a25882397f3a859b9fe1436946140b6756b"}, + {file = "greenlet-3.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:efc6dc8a792243c31f2f5674b670b3a95d46fa1c6a912b8e310d6f542e7b0712"}, + {file = "greenlet-3.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:731e154aba8e757aedd0781d4b240f1225b075b4409f1bb83b05ff410582cf00"}, + {file = "greenlet-3.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:96c20252c2f792defe9a115d3287e14811036d51e78b3aaddbee23b69b216302"}, + {file = "greenlet-3.2.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822"}, + {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83"}, + {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf"}, + {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b"}, + {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147"}, + {file = "greenlet-3.2.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5"}, + {file = "greenlet-3.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc"}, + {file = "greenlet-3.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:751261fc5ad7b6705f5f76726567375bb2104a059454e0226e1eef6c756748ba"}, + {file = "greenlet-3.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:83a8761c75312361aa2b5b903b79da97f13f556164a7dd2d5448655425bd4c34"}, + {file = "greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d"}, + {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b"}, + {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d"}, + {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264"}, + {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688"}, + {file = "greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb"}, + {file = "greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c"}, + {file = "greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163"}, + {file = "greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849"}, + {file = "greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad"}, + {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef"}, + {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3"}, + {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95"}, + {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb"}, + {file = "greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b"}, + {file = "greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0"}, + {file = "greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36"}, + {file = "greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3"}, + {file = "greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86"}, + {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97"}, + {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728"}, + {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a"}, + {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892"}, + {file = "greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141"}, + {file = "greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a"}, + {file = "greenlet-3.2.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:42efc522c0bd75ffa11a71e09cd8a399d83fafe36db250a87cf1dacfaa15dc64"}, + {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d760f9bdfe79bff803bad32b4d8ffb2c1d2ce906313fc10a83976ffb73d64ca7"}, + {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8324319cbd7b35b97990090808fdc99c27fe5338f87db50514959f8059999805"}, + {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:8c37ef5b3787567d322331d5250e44e42b58c8c713859b8a04c6065f27efbf72"}, + {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ce539fb52fb774d0802175d37fcff5c723e2c7d249c65916257f0a940cee8904"}, + {file = "greenlet-3.2.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:003c930e0e074db83559edc8705f3a2d066d4aa8c2f198aff1e454946efd0f26"}, + {file = "greenlet-3.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e70ea4384b81ef9e84192e8a77fb87573138aa5d4feee541d8014e452b434da"}, + {file = "greenlet-3.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:22eb5ba839c4b2156f18f76768233fe44b23a31decd9cc0d4cc8141c211fd1b4"}, + {file = "greenlet-3.2.3-cp39-cp39-win32.whl", hash = "sha256:4532f0d25df67f896d137431b13f4cdce89f7e3d4a96387a41290910df4d3a57"}, + {file = "greenlet-3.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:aaa7aae1e7f75eaa3ae400ad98f8644bb81e1dc6ba47ce8a93d3f17274e08322"}, + {file = "greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + [[package]] name = "griffe" version = "1.7.3" @@ -3629,6 +3698,118 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] +[[package]] +name = "sqlalchemy" +version = "2.0.41" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "SQLAlchemy-2.0.41-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-win32.whl", hash = "sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-win_amd64.whl", hash = "sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-win32.whl", hash = "sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-win_amd64.whl", hash = "sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-win32.whl", hash = "sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-win_amd64.whl", hash = "sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-win32.whl", hash = "sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-win_amd64.whl", hash = "sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-win32.whl", hash = "sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-win_amd64.whl", hash = "sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71"}, + {file = "sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576"}, + {file = "sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9"}, +] + +[package.dependencies] +greenlet = {version = ">=1", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"] +aioodbc = ["aioodbc", "greenlet (>=1)"] +aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (>=1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "sqlmodel" +version = "0.0.24" +description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sqlmodel-0.0.24-py3-none-any.whl", hash = "sha256:6778852f09370908985b667d6a3ab92910d0d5ec88adcaf23dbc242715ff7193"}, + {file = "sqlmodel-0.0.24.tar.gz", hash = "sha256:cc5c7613c1a5533c9c7867e1aab2fd489a76c9e8a061984da11b4e613c182423"}, +] + +[package.dependencies] +pydantic = ">=1.10.13,<3.0.0" +SQLAlchemy = ">=2.0.14,<2.1.0" + [[package]] name = "tabulate" version = "0.9.0" @@ -4300,4 +4481,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "9c4698e9c87a914200bcd559225e4d006f72bae75f5ba4b9bad94b1817ce5fec" +content-hash = "3d04ad623567f4b4954c7e7205d0d74f6968b536d41e04bb7d7e85c80de34e19" From 0564fcb6fea3a194811137bd467cc355b41533d4 Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:45:05 -0500 Subject: [PATCH 08/17] delete(main.prisma) i fucking hate git --- prisma/schema/main.prisma | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 prisma/schema/main.prisma diff --git a/prisma/schema/main.prisma b/prisma/schema/main.prisma deleted file mode 100644 index 9c502a3c..00000000 --- a/prisma/schema/main.prisma +++ /dev/null @@ -1,12 +0,0 @@ -generator client { - provider = "prisma-client-py" - recursive_type_depth = "-1" - interface = "asyncio" - previewFeatures = ["prismaSchemaFolder"] -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") - directUrl = env("DATABASE_URL") -} From 0bb30875da8130dad6ae8354187b92d6aa377d90 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:46:31 +0000 Subject: [PATCH 09/17] style: auto fixes from pre-commit hooks --- prisma/migrations/migration_lock.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml index fbffa92c..99e4f200 100644 --- a/prisma/migrations/migration_lock.toml +++ b/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually # It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file +provider = "postgresql" From eea6dada6a5b10d220b9b7e5d0a2c246a1b4fb6b Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Fri, 20 Jun 2025 14:26:44 -0500 Subject: [PATCH 10/17] fix(schemas.py): temporarily add type ignore --- tux/database/schemas.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tux/database/schemas.py b/tux/database/schemas.py index 9501bedc..ca966d84 100644 --- a/tux/database/schemas.py +++ b/tux/database/schemas.py @@ -1,3 +1,6 @@ +# type: ignore +# TODO: type ignore is a temporary fix, fix when other things are done + from __future__ import annotations from datetime import UTC, datetime From a493f0554f58ea8369024f85e0a6ec9b4975c20a Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Fri, 20 Jun 2025 14:58:40 -0500 Subject: [PATCH 11/17] refactor(database): migrate client from Prisma to SQLModel --- .env.example | 1 + poetry.lock | 96 +++++-- .../migrations/20250405050252_/migration.sql | 247 ------------------ prisma/migrations/migration_lock.toml | 3 - pyproject.toml | 2 +- tux/database/client.py | 162 +++--------- 6 files changed, 110 insertions(+), 401 deletions(-) delete mode 100644 prisma/migrations/20250405050252_/migration.sql delete mode 100644 prisma/migrations/migration_lock.toml diff --git a/.env.example b/.env.example index 13a2e40e..3d880a71 100644 --- a/.env.example +++ b/.env.example @@ -16,6 +16,7 @@ PROD_DATABASE_URL="" # Bot Tokens (Required: one depending on mode) # The application uses DEV_BOT_TOKEN when run with '--dev' flag, # and PROD_BOT_TOKEN otherwise (production mode). +# PREFIX SHOULD BE postgresql+asyncpg:// DEV_BOT_TOKEN="" PROD_BOT_TOKEN="" diff --git a/poetry.lock b/poetry.lock index e50c816b..23aa91d1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -232,6 +232,70 @@ types-python-dateutil = ">=2.8.10" doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] +[[package]] +name = "asyncpg" +version = "0.30.0" +description = "An asyncio PostgreSQL driver" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "asyncpg-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e"}, + {file = "asyncpg-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0"}, + {file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3152fef2e265c9c24eec4ee3d22b4f4d2703d30614b0b6753e9ed4115c8a146f"}, + {file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7255812ac85099a0e1ffb81b10dc477b9973345793776b128a23e60148dd1af"}, + {file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:578445f09f45d1ad7abddbff2a3c7f7c291738fdae0abffbeb737d3fc3ab8b75"}, + {file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c42f6bb65a277ce4d93f3fba46b91a265631c8df7250592dd4f11f8b0152150f"}, + {file = "asyncpg-0.30.0-cp310-cp310-win32.whl", hash = "sha256:aa403147d3e07a267ada2ae34dfc9324e67ccc4cdca35261c8c22792ba2b10cf"}, + {file = "asyncpg-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb622c94db4e13137c4c7f98834185049cc50ee01d8f657ef898b6407c7b9c50"}, + {file = "asyncpg-0.30.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5e0511ad3dec5f6b4f7a9e063591d407eee66b88c14e2ea636f187da1dcfff6a"}, + {file = "asyncpg-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:915aeb9f79316b43c3207363af12d0e6fd10776641a7de8a01212afd95bdf0ed"}, + {file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c198a00cce9506fcd0bf219a799f38ac7a237745e1d27f0e1f66d3707c84a5a"}, + {file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3326e6d7381799e9735ca2ec9fd7be4d5fef5dcbc3cb555d8a463d8460607956"}, + {file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51da377487e249e35bd0859661f6ee2b81db11ad1f4fc036194bc9cb2ead5056"}, + {file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc6d84136f9c4d24d358f3b02be4b6ba358abd09f80737d1ac7c444f36108454"}, + {file = "asyncpg-0.30.0-cp311-cp311-win32.whl", hash = "sha256:574156480df14f64c2d76450a3f3aaaf26105869cad3865041156b38459e935d"}, + {file = "asyncpg-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:3356637f0bd830407b5597317b3cb3571387ae52ddc3bca6233682be88bbbc1f"}, + {file = "asyncpg-0.30.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c902a60b52e506d38d7e80e0dd5399f657220f24635fee368117b8b5fce1142e"}, + {file = "asyncpg-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aca1548e43bbb9f0f627a04666fedaca23db0a31a84136ad1f868cb15deb6e3a"}, + {file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c2a2ef565400234a633da0eafdce27e843836256d40705d83ab7ec42074efb3"}, + {file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1292b84ee06ac8a2ad8e51c7475aa309245874b61333d97411aab835c4a2f737"}, + {file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f5712350388d0cd0615caec629ad53c81e506b1abaaf8d14c93f54b35e3595a"}, + {file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db9891e2d76e6f425746c5d2da01921e9a16b5a71a1c905b13f30e12a257c4af"}, + {file = "asyncpg-0.30.0-cp312-cp312-win32.whl", hash = "sha256:68d71a1be3d83d0570049cd1654a9bdfe506e794ecc98ad0873304a9f35e411e"}, + {file = "asyncpg-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a0292c6af5c500523949155ec17b7fe01a00ace33b68a476d6b5059f9630305"}, + {file = "asyncpg-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70"}, + {file = "asyncpg-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3"}, + {file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33"}, + {file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4"}, + {file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4"}, + {file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba"}, + {file = "asyncpg-0.30.0-cp313-cp313-win32.whl", hash = "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590"}, + {file = "asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e"}, + {file = "asyncpg-0.30.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ff1fc8b5bf724273782ff8b4f57b0f8220a1b2324184846b39d1ab4122031d"}, + {file = "asyncpg-0.30.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64e899bce0600871b55368b8483e5e3e7f1860c9482e7f12e0a771e747988168"}, + {file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b290f4726a887f75dcd1b3006f484252db37602313f806e9ffc4e5996cfe5cb"}, + {file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f86b0e2cd3f1249d6fe6fd6cfe0cd4538ba994e2d8249c0491925629b9104d0f"}, + {file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:393af4e3214c8fa4c7b86da6364384c0d1b3298d45803375572f415b6f673f38"}, + {file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fd4406d09208d5b4a14db9a9dbb311b6d7aeeab57bded7ed2f8ea41aeef39b34"}, + {file = "asyncpg-0.30.0-cp38-cp38-win32.whl", hash = "sha256:0b448f0150e1c3b96cb0438a0d0aa4871f1472e58de14a3ec320dbb2798fb0d4"}, + {file = "asyncpg-0.30.0-cp38-cp38-win_amd64.whl", hash = "sha256:f23b836dd90bea21104f69547923a02b167d999ce053f3d502081acea2fba15b"}, + {file = "asyncpg-0.30.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f4e83f067b35ab5e6371f8a4c93296e0439857b4569850b178a01385e82e9ad"}, + {file = "asyncpg-0.30.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5df69d55add4efcd25ea2a3b02025b669a285b767bfbf06e356d68dbce4234ff"}, + {file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3479a0d9a852c7c84e822c073622baca862d1217b10a02dd57ee4a7a081f708"}, + {file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26683d3b9a62836fad771a18ecf4659a30f348a561279d6227dab96182f46144"}, + {file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1b982daf2441a0ed314bd10817f1606f1c28b1136abd9e4f11335358c2c631cb"}, + {file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1c06a3a50d014b303e5f6fc1e5f95eb28d2cee89cf58384b700da621e5d5e547"}, + {file = "asyncpg-0.30.0-cp39-cp39-win32.whl", hash = "sha256:1b11a555a198b08f5c4baa8f8231c74a366d190755aa4f99aacec5970afe929a"}, + {file = "asyncpg-0.30.0-cp39-cp39-win_amd64.whl", hash = "sha256:8b684a3c858a83cd876f05958823b68e8d14ec01bb0c0d14a6704c5bf9711773"}, + {file = "asyncpg-0.30.0.tar.gz", hash = "sha256:c551e9928ab6707602f44811817f82ba3c446e018bfe1d3abecc8ba5f3eac851"}, +] + +[package.extras] +docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"] +gssauth = ["gssapi ; platform_system != \"Windows\"", "sspilib ; platform_system == \"Windows\""] +test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi ; platform_system == \"Linux\"", "k5test ; platform_system == \"Linux\"", "mypy (>=1.8.0,<1.9.0)", "sspilib ; platform_system == \"Windows\"", "uvloop (>=0.15.3) ; platform_system != \"Windows\" and python_version < \"3.14.0\""] + [[package]] name = "asynctempfile" version = "0.5.0" @@ -2510,7 +2574,7 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -2808,32 +2872,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "prisma" -version = "0.15.0" -description = "Prisma Client Python is an auto-generated and fully type-safe database client" -optional = false -python-versions = ">=3.8.0" -groups = ["main"] -files = [ - {file = "prisma-0.15.0-py3-none-any.whl", hash = "sha256:de949cc94d3d91243615f22ff64490aa6e2d7cb81aabffce53d92bd3977c09a4"}, - {file = "prisma-0.15.0.tar.gz", hash = "sha256:5cd6402aa8322625db3fc1152040404e7fc471fe7f8fa3a314fa8a99529ca107"}, -] - -[package.dependencies] -click = ">=7.1.2" -httpx = ">=0.19.0" -jinja2 = ">=2.11.2" -nodeenv = "*" -pydantic = ">=1.10.0,<3" -python-dotenv = ">=0.12.0" -tomlkit = "*" -typing-extensions = ">=4.5.0" - -[package.extras] -all = ["nodejs-bin"] -node = ["nodejs-bin"] - [[package]] name = "propcache" version = "0.3.2" @@ -4278,7 +4316,7 @@ version = "0.13.3" description = "Style preserving TOML library" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, @@ -4973,4 +5011,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "0a82091dad719c0e2ec2fb410829b51d7156eed8b588de7e03918d70a2ac8580" +content-hash = "a9aa2a662ee924e16bb787b90c1913537776865380fa2856ae159ef89791b941" diff --git a/prisma/migrations/20250405050252_/migration.sql b/prisma/migrations/20250405050252_/migration.sql deleted file mode 100644 index 8ea45a06..00000000 --- a/prisma/migrations/20250405050252_/migration.sql +++ /dev/null @@ -1,247 +0,0 @@ --- CreateEnum -CREATE TYPE "CaseType" AS ENUM ('BAN', 'UNBAN', 'HACKBAN', 'TEMPBAN', 'KICK', 'SNIPPETBAN', 'TIMEOUT', 'UNTIMEOUT', 'WARN', 'JAIL', 'UNJAIL', 'SNIPPETUNBAN', 'UNTEMPBAN', 'POLLBAN', 'POLLUNBAN'); - --- CreateTable -CREATE TABLE "AFKModel" ( - "member_id" BIGINT NOT NULL, - "nickname" TEXT NOT NULL, - "reason" TEXT NOT NULL, - "since" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "guild_id" BIGINT NOT NULL, - "perm_afk" BOOLEAN NOT NULL DEFAULT false, - - CONSTRAINT "AFKModel_pkey" PRIMARY KEY ("member_id") -); - --- CreateTable -CREATE TABLE "Note" ( - "note_id" BIGSERIAL NOT NULL, - "note_content" TEXT NOT NULL, - "note_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "note_moderator_id" BIGINT NOT NULL, - "note_user_id" BIGINT NOT NULL, - "note_number" BIGINT, - "guild_id" BIGINT NOT NULL, - - CONSTRAINT "Note_pkey" PRIMARY KEY ("note_id") -); - --- CreateTable -CREATE TABLE "Case" ( - "case_id" BIGSERIAL NOT NULL, - "case_status" BOOLEAN DEFAULT true, - "case_type" "CaseType" NOT NULL, - "case_reason" TEXT NOT NULL, - "case_moderator_id" BIGINT NOT NULL, - "case_user_id" BIGINT NOT NULL, - "case_user_roles" BIGINT[] DEFAULT ARRAY[]::BIGINT[], - "case_number" BIGINT, - "case_created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, - "case_expires_at" TIMESTAMP(3), - "case_tempban_expired" BOOLEAN DEFAULT false, - "guild_id" BIGINT NOT NULL, - - CONSTRAINT "Case_pkey" PRIMARY KEY ("case_id") -); - --- CreateTable -CREATE TABLE "Reminder" ( - "reminder_id" BIGSERIAL NOT NULL, - "reminder_content" TEXT NOT NULL, - "reminder_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "reminder_expires_at" TIMESTAMP(3) NOT NULL, - "reminder_channel_id" BIGINT NOT NULL, - "reminder_user_id" BIGINT NOT NULL, - "reminder_sent" BOOLEAN NOT NULL DEFAULT false, - "guild_id" BIGINT NOT NULL, - - CONSTRAINT "Reminder_pkey" PRIMARY KEY ("reminder_id") -); - --- CreateTable -CREATE TABLE "Snippet" ( - "snippet_id" BIGSERIAL NOT NULL, - "snippet_name" TEXT NOT NULL, - "snippet_content" TEXT NOT NULL, - "snippet_user_id" BIGINT NOT NULL, - "snippet_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "guild_id" BIGINT NOT NULL, - "uses" BIGINT NOT NULL DEFAULT 0, - "locked" BOOLEAN NOT NULL DEFAULT false, - - CONSTRAINT "Snippet_pkey" PRIMARY KEY ("snippet_id") -); - --- CreateTable -CREATE TABLE "GuildConfig" ( - "prefix" TEXT, - "mod_log_id" BIGINT, - "audit_log_id" BIGINT, - "join_log_id" BIGINT, - "private_log_id" BIGINT, - "report_log_id" BIGINT, - "dev_log_id" BIGINT, - "jail_channel_id" BIGINT, - "general_channel_id" BIGINT, - "starboard_channel_id" BIGINT, - "perm_level_0_role_id" BIGINT, - "perm_level_1_role_id" BIGINT, - "perm_level_2_role_id" BIGINT, - "perm_level_3_role_id" BIGINT, - "perm_level_4_role_id" BIGINT, - "perm_level_5_role_id" BIGINT, - "perm_level_6_role_id" BIGINT, - "perm_level_7_role_id" BIGINT, - "base_staff_role_id" BIGINT, - "base_member_role_id" BIGINT, - "jail_role_id" BIGINT, - "quarantine_role_id" BIGINT, - "guild_id" BIGINT NOT NULL, - - CONSTRAINT "GuildConfig_pkey" PRIMARY KEY ("guild_id") -); - --- CreateTable -CREATE TABLE "Guild" ( - "guild_id" BIGINT NOT NULL, - "guild_joined_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, - "case_count" BIGINT NOT NULL DEFAULT 0, - - CONSTRAINT "Guild_pkey" PRIMARY KEY ("guild_id") -); - --- CreateTable -CREATE TABLE "Levels" ( - "member_id" BIGINT NOT NULL, - "xp" DOUBLE PRECISION NOT NULL DEFAULT 0, - "level" BIGINT NOT NULL DEFAULT 0, - "blacklisted" BOOLEAN NOT NULL DEFAULT false, - "last_message" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "guild_id" BIGINT NOT NULL, - - CONSTRAINT "Levels_pkey" PRIMARY KEY ("member_id","guild_id") -); - --- CreateTable -CREATE TABLE "Starboard" ( - "guild_id" BIGINT NOT NULL, - "starboard_channel_id" BIGINT NOT NULL, - "starboard_emoji" TEXT NOT NULL, - "starboard_threshold" INTEGER NOT NULL, - - CONSTRAINT "Starboard_pkey" PRIMARY KEY ("guild_id") -); - --- CreateTable -CREATE TABLE "StarboardMessage" ( - "message_id" BIGINT NOT NULL, - "message_content" TEXT NOT NULL, - "message_created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "message_expires_at" TIMESTAMP(3) NOT NULL, - "message_channel_id" BIGINT NOT NULL, - "message_user_id" BIGINT NOT NULL, - "message_guild_id" BIGINT NOT NULL, - "star_count" INTEGER NOT NULL DEFAULT 0, - "starboard_message_id" BIGINT NOT NULL, - - CONSTRAINT "StarboardMessage_pkey" PRIMARY KEY ("message_id") -); - --- CreateIndex -CREATE INDEX "AFKModel_member_id_idx" ON "AFKModel"("member_id"); - --- CreateIndex -CREATE UNIQUE INDEX "AFKModel_member_id_guild_id_key" ON "AFKModel"("member_id", "guild_id"); - --- CreateIndex -CREATE INDEX "Note_note_number_guild_id_idx" ON "Note"("note_number", "guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "Note_note_number_guild_id_key" ON "Note"("note_number", "guild_id"); - --- CreateIndex -CREATE INDEX "Case_case_number_guild_id_idx" ON "Case"("case_number", "guild_id"); - --- CreateIndex -CREATE INDEX "Case_guild_id_case_user_id_idx" ON "Case"("guild_id", "case_user_id"); - --- CreateIndex -CREATE INDEX "Case_guild_id_case_moderator_id_idx" ON "Case"("guild_id", "case_moderator_id"); - --- CreateIndex -CREATE INDEX "Case_guild_id_case_type_idx" ON "Case"("guild_id", "case_type"); - --- CreateIndex -CREATE INDEX "Case_case_type_case_expires_at_case_tempban_expired_idx" ON "Case"("case_type", "case_expires_at", "case_tempban_expired"); - --- CreateIndex -CREATE INDEX "Case_case_created_at_idx" ON "Case"("case_created_at" DESC); - --- CreateIndex -CREATE UNIQUE INDEX "Case_case_number_guild_id_key" ON "Case"("case_number", "guild_id"); - --- CreateIndex -CREATE INDEX "Reminder_reminder_id_guild_id_idx" ON "Reminder"("reminder_id", "guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "Reminder_reminder_id_guild_id_key" ON "Reminder"("reminder_id", "guild_id"); - --- CreateIndex -CREATE INDEX "Snippet_snippet_name_guild_id_idx" ON "Snippet"("snippet_name", "guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "Snippet_snippet_name_guild_id_key" ON "Snippet"("snippet_name", "guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "GuildConfig_guild_id_key" ON "GuildConfig"("guild_id"); - --- CreateIndex -CREATE INDEX "GuildConfig_guild_id_idx" ON "GuildConfig"("guild_id"); - --- CreateIndex -CREATE INDEX "Guild_guild_id_idx" ON "Guild"("guild_id"); - --- CreateIndex -CREATE INDEX "Levels_member_id_idx" ON "Levels"("member_id"); - --- CreateIndex -CREATE UNIQUE INDEX "Levels_member_id_guild_id_key" ON "Levels"("member_id", "guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "Starboard_guild_id_key" ON "Starboard"("guild_id"); - --- CreateIndex -CREATE INDEX "Starboard_guild_id_idx" ON "Starboard"("guild_id"); - --- CreateIndex -CREATE INDEX "StarboardMessage_message_id_message_guild_id_idx" ON "StarboardMessage"("message_id", "message_guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "StarboardMessage_message_id_message_guild_id_key" ON "StarboardMessage"("message_id", "message_guild_id"); - --- AddForeignKey -ALTER TABLE "AFKModel" ADD CONSTRAINT "AFKModel_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Note" ADD CONSTRAINT "Note_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Case" ADD CONSTRAINT "Case_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Snippet" ADD CONSTRAINT "Snippet_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "GuildConfig" ADD CONSTRAINT "GuildConfig_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Levels" ADD CONSTRAINT "Levels_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Starboard" ADD CONSTRAINT "Starboard_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "StarboardMessage" ADD CONSTRAINT "StarboardMessage_message_guild_id_fkey" FOREIGN KEY ("message_guild_id") REFERENCES "Guild"("guild_id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml deleted file mode 100644 index 99e4f200..00000000 --- a/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "postgresql" diff --git a/pyproject.toml b/pyproject.toml index bf8a913d..a595f4c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ httpx = ">=0.28.0" jishaku = ">=2.5.2" loguru = ">=0.7.2" pillow = ">=11.2.1,<11.3.0" -prisma = ">=0.15.0" psutil = ">=6.0.0" pynacl = ">=1.5.0" python-dotenv = ">=1.0.1" @@ -53,6 +52,7 @@ click = "^8.1.8" levenshtein = "^0.27.1" jinja2 = "^3.1.6" sqlmodel = "^0.0.24" +asyncpg = "^0.30.0" [tool.poetry.group.dev.dependencies] pre-commit = "==4.2.0" diff --git a/tux/database/client.py b/tux/database/client.py index d3c5fa34..675457a2 100644 --- a/tux/database/client.py +++ b/tux/database/client.py @@ -1,10 +1,9 @@ -from collections.abc import AsyncGenerator -from contextlib import asynccontextmanager from typing import TypeVar -from loguru import logger +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlmodel import SQLModel -from prisma import Prisma +from tux.utils.config import CONFIG T = TypeVar("T") @@ -14,141 +13,62 @@ class DatabaseClient: - """A singleton database client that manages the Prisma connection. + """A singleton database client that manages the SQLModel connection. This class provides a centralized way to manage the database connection and ensures proper connection handling throughout the application lifecycle. """ - _instance = None - _client: Prisma | None = None + # Async engine for Postgres + engine = create_async_engine(CONFIG.DATABASE_URL, echo=True, future=True) + # Async session factory + SessionLocal = async_sessionmaker( + bind=engine, + class_=AsyncSession, + expire_on_commit=False, + ) - def __new__(cls): - if cls._instance is None: - cls._instance = super().__new__(cls) - return cls._instance + def __init__(self) -> None: + # Track whether connect() and init_db() have run + self._connected = False + self._registered = False - @property - def client(self) -> Prisma: - """Get the Prisma client instance. - - Returns - ------- - Prisma - The Prisma client instance. + async def connect(self) -> None: + """Establish a test connection and initialize database tables.""" + if self._connected: + raise RuntimeError(CLIENT_ALREADY_CONNECTED) + # Create tables and test engine + async with self.engine.begin() as conn: + await conn.run_sync(SQLModel.metadata.create_all) + self._connected = True + self._registered = True - Raises - ------ - RuntimeError - If the client is not connected. - """ - if self._client is None: - raise RuntimeError(CLIENT_NOT_CONNECTED) - return self._client + async def disconnect(self) -> None: + """Dispose the engine and reset connection state.""" + await self.engine.dispose() + self._connected = False + self._registered = False def is_connected(self) -> bool: - """Check if the database client is connected. - - Returns - ------- - bool - True if the client is connected, False otherwise. - """ - return self._client is not None + """Return True if connect() has been successfully called.""" + return self._connected def is_registered(self) -> bool: - """Check if the database client is properly registered. + """Return True if tables have been created.""" + return self._registered - Returns - ------- - bool - True if the client is registered with models, False otherwise. + async def init_db(self) -> None: """ - # Since we use auto_register=True in connect(), if connected then registered - return self.is_connected() - - async def connect(self) -> None: - """Connect to the database. - - This method establishes the database connection and performs - any necessary initialization. - - Notes - ----- - The DATABASE_URL environment variable should be set before calling - this method, which is handled by the tux.utils.env module. + Create all tables defined in SQLModel metadata. """ - if self._client is not None: - logger.warning(CLIENT_ALREADY_CONNECTED) - return - - try: - self._client = Prisma( - log_queries=False, - auto_register=True, - ) - await self._client.connect() - logger.info("Successfully connected to database.") - except Exception as e: - logger.error(f"Failed to connect to database: {e}") - raise + async with self.engine.begin() as conn: + await conn.run_sync(SQLModel.metadata.create_all) - async def disconnect(self) -> None: - """Disconnect from the database. - - This method closes the database connection and performs - any necessary cleanup. - """ - if self._client is None: - logger.warning("Database client is not connected.") - return - - try: - await self._client.disconnect() - self._client = None - logger.info("Successfully disconnected from database.") - except Exception as e: - logger.error(f"Failed to disconnect from database: {e}") - raise - - @asynccontextmanager - async def transaction(self) -> AsyncGenerator[None]: - """Create a database transaction. - - This context manager ensures that database operations are atomic - and handles rollback in case of errors. - - Yields - ------ - None - Control is yielded to the caller within the transaction. + def get_session(self) -> AsyncSession: """ - if self._client is None: - raise RuntimeError(CLIENT_NOT_CONNECTED) - - async with self._client.batch_() as _: - try: - yield - except Exception as e: - logger.error(f"Transaction failed, rolling back: {e}") - raise - - async def batch(self) -> AsyncGenerator[None]: - """Create a batch operation context. - - This context manager allows batching multiple write operations - into a single database call for better performance. - - Yields - ------ - None - Control is yielded to the caller within the batch context. + Return a new AsyncSession. Use with `async with` context or close manually. """ - if self._client is None: - raise RuntimeError(CLIENT_NOT_CONNECTED) - - async with self._client.batch_() as _: - yield + return self.SessionLocal() # Global database client instance From a984037898194e061de8c8285e1a863a0be8e8d3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:58:59 +0000 Subject: [PATCH 12/17] style: auto fixes from pre-commit hooks --- tests/unit/tux/utils/test_exceptions.py | 2 +- tux/cogs/moderation/__init__.py | 2 +- tux/cogs/moderation/ban.py | 2 +- tux/cogs/moderation/cases.py | 4 ++-- tux/cogs/moderation/jail.py | 2 +- tux/cogs/moderation/kick.py | 2 +- tux/cogs/moderation/pollban.py | 2 +- tux/cogs/moderation/pollunban.py | 2 +- tux/cogs/moderation/snippetban.py | 2 +- tux/cogs/moderation/snippetunban.py | 2 +- tux/cogs/moderation/tempban.py | 2 +- tux/cogs/moderation/timeout.py | 2 +- tux/cogs/moderation/unban.py | 2 +- tux/cogs/moderation/unjail.py | 2 +- tux/cogs/moderation/untimeout.py | 2 +- tux/cogs/moderation/warn.py | 2 +- tux/cogs/snippets/__init__.py | 2 +- tux/cogs/snippets/list_snippets.py | 2 +- tux/cogs/utility/afk.py | 2 +- tux/cogs/utility/poll.py | 2 +- tux/cogs/utility/remindme.py | 2 +- tux/database/controllers/afk.py | 1 + tux/database/controllers/base.py | 2 +- tux/database/controllers/case.py | 1 + tux/database/controllers/guild.py | 1 + tux/database/controllers/guild_config.py | 2 +- tux/database/controllers/levels.py | 2 +- tux/database/controllers/note.py | 1 + tux/database/controllers/reminder.py | 1 + tux/database/controllers/snippet.py | 1 + tux/database/controllers/starboard.py | 1 + tux/utils/converters.py | 1 - tux/utils/flags.py | 2 +- 33 files changed, 33 insertions(+), 27 deletions(-) diff --git a/tests/unit/tux/utils/test_exceptions.py b/tests/unit/tux/utils/test_exceptions.py index fb7ae13f..67c606a9 100644 --- a/tests/unit/tux/utils/test_exceptions.py +++ b/tests/unit/tux/utils/test_exceptions.py @@ -4,8 +4,8 @@ from unittest.mock import Mock import pytest - from prisma.models import Case + from tux.utils.exceptions import ( APIConnectionError, APIRequestError, diff --git a/tux/cogs/moderation/__init__.py b/tux/cogs/moderation/__init__.py index 1f0c8be9..b501c2b3 100644 --- a/tux/cogs/moderation/__init__.py +++ b/tux/cogs/moderation/__init__.py @@ -7,8 +7,8 @@ import discord from discord.ext import commands from loguru import logger - from prisma.enums import CaseType + from tux.bot import Tux from tux.database.controllers import DatabaseController from tux.ui.embeds import EmbedCreator, EmbedType diff --git a/tux/cogs/moderation/ban.py b/tux/cogs/moderation/ban.py index 5f0b2c2a..2c41e1aa 100644 --- a/tux/cogs/moderation/ban.py +++ b/tux/cogs/moderation/ban.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import BanFlags diff --git a/tux/cogs/moderation/cases.py b/tux/cogs/moderation/cases.py index 31e486fa..573aba5e 100644 --- a/tux/cogs/moderation/cases.py +++ b/tux/cogs/moderation/cases.py @@ -3,11 +3,11 @@ import discord from discord.ext import commands from loguru import logger -from reactionmenu import ViewButton, ViewMenu - from prisma.enums import CaseType from prisma.models import Case from prisma.types import CaseWhereInput +from reactionmenu import ViewButton, ViewMenu + from tux.bot import Tux from tux.ui.embeds import EmbedCreator, EmbedType from tux.utils import checks diff --git a/tux/cogs/moderation/jail.py b/tux/cogs/moderation/jail.py index 89ddf066..96c98e9a 100644 --- a/tux/cogs/moderation/jail.py +++ b/tux/cogs/moderation/jail.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands from loguru import logger - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import JailFlags diff --git a/tux/cogs/moderation/kick.py b/tux/cogs/moderation/kick.py index 4b37bc4f..90aa80c8 100644 --- a/tux/cogs/moderation/kick.py +++ b/tux/cogs/moderation/kick.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import KickFlags diff --git a/tux/cogs/moderation/pollban.py b/tux/cogs/moderation/pollban.py index bca4ad61..93b6afe6 100644 --- a/tux/cogs/moderation/pollban.py +++ b/tux/cogs/moderation/pollban.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import PollBanFlags diff --git a/tux/cogs/moderation/pollunban.py b/tux/cogs/moderation/pollunban.py index 7de59552..48d2972c 100644 --- a/tux/cogs/moderation/pollunban.py +++ b/tux/cogs/moderation/pollunban.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import PollUnbanFlags diff --git a/tux/cogs/moderation/snippetban.py b/tux/cogs/moderation/snippetban.py index 2b90fc69..03a152f9 100644 --- a/tux/cogs/moderation/snippetban.py +++ b/tux/cogs/moderation/snippetban.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import SnippetBanFlags diff --git a/tux/cogs/moderation/snippetunban.py b/tux/cogs/moderation/snippetunban.py index 59179bb7..bb3ef17d 100644 --- a/tux/cogs/moderation/snippetunban.py +++ b/tux/cogs/moderation/snippetunban.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import SnippetUnbanFlags diff --git a/tux/cogs/moderation/tempban.py b/tux/cogs/moderation/tempban.py index 4641de85..a0fa04ba 100644 --- a/tux/cogs/moderation/tempban.py +++ b/tux/cogs/moderation/tempban.py @@ -3,9 +3,9 @@ import discord from discord.ext import commands, tasks from loguru import logger - from prisma.enums import CaseType from prisma.models import Case + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import TempBanFlags diff --git a/tux/cogs/moderation/timeout.py b/tux/cogs/moderation/timeout.py index d47b1d14..a2fbc223 100644 --- a/tux/cogs/moderation/timeout.py +++ b/tux/cogs/moderation/timeout.py @@ -2,8 +2,8 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import TimeoutFlags diff --git a/tux/cogs/moderation/unban.py b/tux/cogs/moderation/unban.py index c2fc5a6f..bec74e87 100644 --- a/tux/cogs/moderation/unban.py +++ b/tux/cogs/moderation/unban.py @@ -2,8 +2,8 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.constants import CONST diff --git a/tux/cogs/moderation/unjail.py b/tux/cogs/moderation/unjail.py index 761b0bbe..f0aaf679 100644 --- a/tux/cogs/moderation/unjail.py +++ b/tux/cogs/moderation/unjail.py @@ -3,9 +3,9 @@ import discord from discord.ext import commands from loguru import logger - from prisma.enums import CaseType from prisma.models import Case + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import UnjailFlags diff --git a/tux/cogs/moderation/untimeout.py b/tux/cogs/moderation/untimeout.py index 86733e7f..6dedfd87 100644 --- a/tux/cogs/moderation/untimeout.py +++ b/tux/cogs/moderation/untimeout.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import UntimeoutFlags diff --git a/tux/cogs/moderation/warn.py b/tux/cogs/moderation/warn.py index 6bbee647..bab8b6fd 100644 --- a/tux/cogs/moderation/warn.py +++ b/tux/cogs/moderation/warn.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.bot import Tux from tux.utils import checks from tux.utils.flags import WarnFlags diff --git a/tux/cogs/snippets/__init__.py b/tux/cogs/snippets/__init__.py index d7e49cce..4ca02c62 100644 --- a/tux/cogs/snippets/__init__.py +++ b/tux/cogs/snippets/__init__.py @@ -1,9 +1,9 @@ import discord from discord.ext import commands from loguru import logger - from prisma.enums import CaseType from prisma.models import Snippet + from tux.bot import Tux from tux.database.controllers import DatabaseController from tux.ui.embeds import EmbedCreator, EmbedType diff --git a/tux/cogs/snippets/list_snippets.py b/tux/cogs/snippets/list_snippets.py index 0a60756a..ec958ee7 100644 --- a/tux/cogs/snippets/list_snippets.py +++ b/tux/cogs/snippets/list_snippets.py @@ -1,7 +1,7 @@ from discord.ext import commands +from prisma.models import Snippet from reactionmenu import ViewButton, ViewMenu -from prisma.models import Snippet from tux.bot import Tux from tux.utils.constants import CONST from tux.utils.functions import generate_usage diff --git a/tux/cogs/utility/afk.py b/tux/cogs/utility/afk.py index bafaec05..ca7f9dd8 100644 --- a/tux/cogs/utility/afk.py +++ b/tux/cogs/utility/afk.py @@ -6,8 +6,8 @@ import discord from discord.ext import commands, tasks - from prisma.models import AFKModel + from tux.bot import Tux from tux.cogs.utility import add_afk, del_afk from tux.database.controllers import DatabaseController diff --git a/tux/cogs/utility/poll.py b/tux/cogs/utility/poll.py index fb75a298..2d28ba04 100644 --- a/tux/cogs/utility/poll.py +++ b/tux/cogs/utility/poll.py @@ -2,8 +2,8 @@ from discord import app_commands from discord.ext import commands from loguru import logger - from prisma.enums import CaseType + from tux.bot import Tux from tux.database.controllers import DatabaseController from tux.ui.embeds import EmbedCreator diff --git a/tux/cogs/utility/remindme.py b/tux/cogs/utility/remindme.py index b7f6662a..f42f35fe 100644 --- a/tux/cogs/utility/remindme.py +++ b/tux/cogs/utility/remindme.py @@ -4,8 +4,8 @@ import discord from discord.ext import commands, tasks from loguru import logger - from prisma.models import Reminder + from tux.bot import Tux from tux.database.controllers import DatabaseController from tux.ui.embeds import EmbedCreator diff --git a/tux/database/controllers/afk.py b/tux/database/controllers/afk.py index bb39cd71..c169f22e 100644 --- a/tux/database/controllers/afk.py +++ b/tux/database/controllers/afk.py @@ -2,6 +2,7 @@ from prisma.actions import GuildActions from prisma.models import AFKModel, Guild + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/base.py b/tux/database/controllers/base.py index f407e480..29044a22 100644 --- a/tux/database/controllers/base.py +++ b/tux/database/controllers/base.py @@ -5,7 +5,6 @@ import sentry_sdk from loguru import logger - from prisma.models import ( AFKModel, Case, @@ -18,6 +17,7 @@ Starboard, StarboardMessage, ) + from tux.database.client import db # Explicitly define ModelType to cover all potential models used by controllers diff --git a/tux/database/controllers/case.py b/tux/database/controllers/case.py index 1558a0f3..1fe5b742 100644 --- a/tux/database/controllers/case.py +++ b/tux/database/controllers/case.py @@ -5,6 +5,7 @@ from prisma.enums import CaseType from prisma.models import Case, Guild from prisma.types import CaseWhereInput + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/guild.py b/tux/database/controllers/guild.py index 5e3aeb22..6ee29e26 100644 --- a/tux/database/controllers/guild.py +++ b/tux/database/controllers/guild.py @@ -1,6 +1,7 @@ from typing import Any from prisma.models import Guild + from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/guild_config.py b/tux/database/controllers/guild_config.py index 5acda655..a9b03928 100644 --- a/tux/database/controllers/guild_config.py +++ b/tux/database/controllers/guild_config.py @@ -1,13 +1,13 @@ from typing import Any from loguru import logger - from prisma.actions import GuildActions, GuildConfigActions from prisma.models import Guild, GuildConfig from prisma.types import ( GuildConfigScalarFieldKeys, GuildConfigUpdateInput, ) + from tux.database.client import db diff --git a/tux/database/controllers/levels.py b/tux/database/controllers/levels.py index 87d39af7..294e3b20 100644 --- a/tux/database/controllers/levels.py +++ b/tux/database/controllers/levels.py @@ -2,9 +2,9 @@ import math from loguru import logger - from prisma.actions import GuildActions from prisma.models import Guild, Levels + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/note.py b/tux/database/controllers/note.py index 4ffe05cb..1178fedb 100644 --- a/tux/database/controllers/note.py +++ b/tux/database/controllers/note.py @@ -1,5 +1,6 @@ from prisma.actions import GuildActions from prisma.models import Guild, Note + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/reminder.py b/tux/database/controllers/reminder.py index 4d80a3c1..fb1ca045 100644 --- a/tux/database/controllers/reminder.py +++ b/tux/database/controllers/reminder.py @@ -2,6 +2,7 @@ from prisma.actions import GuildActions from prisma.models import Guild, Reminder + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/snippet.py b/tux/database/controllers/snippet.py index 723c957e..a052c60f 100644 --- a/tux/database/controllers/snippet.py +++ b/tux/database/controllers/snippet.py @@ -2,6 +2,7 @@ from prisma.actions import GuildActions from prisma.models import Guild, Snippet + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/database/controllers/starboard.py b/tux/database/controllers/starboard.py index fc1af494..b79b0b43 100644 --- a/tux/database/controllers/starboard.py +++ b/tux/database/controllers/starboard.py @@ -2,6 +2,7 @@ from prisma.actions import GuildActions from prisma.models import Guild, Starboard, StarboardMessage + from tux.database.client import db from tux.database.controllers.base import BaseController diff --git a/tux/utils/converters.py b/tux/utils/converters.py index dde89f0e..776ee4cf 100644 --- a/tux/utils/converters.py +++ b/tux/utils/converters.py @@ -2,7 +2,6 @@ from typing import Any from discord.ext import commands - from prisma.enums import CaseType time_regex = re.compile(r"(\d{1,5}(?:[.,]?\d{1,5})?)([smhd])") diff --git a/tux/utils/flags.py b/tux/utils/flags.py index 2b636ac9..6cc56fa0 100644 --- a/tux/utils/flags.py +++ b/tux/utils/flags.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands - from prisma.enums import CaseType + from tux.utils.constants import CONST from tux.utils.converters import CaseTypeConverter, TimeConverter, convert_bool From 8e6818ce1bb01eab30c64f33ba219eb93a6db61c Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Sun, 22 Jun 2025 18:27:20 -0500 Subject: [PATCH 13/17] fix(base.py): start controller migration --- tux/database/controllers/base.py | 243 ++++++++++++------------------- 1 file changed, 92 insertions(+), 151 deletions(-) diff --git a/tux/database/controllers/base.py b/tux/database/controllers/base.py index 29044a22..a147a8e8 100644 --- a/tux/database/controllers/base.py +++ b/tux/database/controllers/base.py @@ -3,9 +3,15 @@ from collections.abc import Callable from typing import Any, TypeVar -import sentry_sdk from loguru import logger -from prisma.models import ( +from sqlalchemy import delete as sa_delete +from sqlalchemy import func +from sqlalchemy import update as sa_update +from sqlalchemy.ext.asyncio import AsyncSession +from sqlmodel import select + +from tux.database.client import db +from tux.database.schemas import ( AFKModel, Case, Guild, @@ -18,11 +24,10 @@ StarboardMessage, ) -from tux.database.client import db - # Explicitly define ModelType to cover all potential models used by controllers ModelType = TypeVar( "ModelType", + AFKModel, Case, Guild, Note, @@ -31,7 +36,6 @@ Starboard, StarboardMessage, GuildConfig, - AFKModel, Levels, ) @@ -55,78 +59,33 @@ class BaseController[ """Provides a base interface for database table controllers. This generic class offers common CRUD (Create, Read, Update, Delete) - operations and utility methods for interacting with a specific Prisma model + operations and utility methods for interacting with a specific SQLModel model table. It standardizes database interactions and error handling. Attributes ---------- table : Any - The Prisma client's model instance for the specific table. + The SQLModel client's model instance for the specific table. table_name : str The name of the database table this controller manages. """ - def __init__(self, table_name: str) -> None: + def __init__(self, table: type[ModelType], session: AsyncSession | None = None) -> None: """Initializes the BaseController for a specific table. Parameters ---------- + session : AsyncSession, optional + An optional SQLAlchemy AsyncSession instance. If not provided, + the default session from the database client will be used. table_name : str - The name of the Prisma model table (e.g., 'case', 'guild'). - This name must match an attribute on the Prisma client instance. + The name of the table this controller will manage, used for logging and error messages. """ - self.table: Any = getattr(db.client, table_name) - self.table_name = table_name + self.session = session or db.get_session() + self.table = table # --- Private Helper Methods --- - async def _execute_query( - self, - operation: Callable[[], Any], - error_msg: str, - ) -> Any: - """Executes a database query with standardized error logging. - - Wraps the Prisma client operation call in a try-except block, - logging any exceptions with a contextual error message. - - Parameters - ---------- - operation : Callable[[], Any] - A zero-argument function (e.g., a lambda) that performs the database call. - error_msg : str - The base error message to log if an exception occurs. - - Returns - ------- - Any - The result of the database operation. - - Raises - ------ - Exception - Re-raises any exception caught during the database operation. - """ - # Create a Sentry span to track database query performance - if sentry_sdk.is_initialized(): - with sentry_sdk.start_span(op="db.query", description=f"Database query: {self.table_name}") as span: - span.set_tag("db.table", self.table_name) - try: - result = await operation() - span.set_status("ok") - return result # noqa: TRY300 - except Exception as e: - span.set_status("internal_error") - span.set_data("error", str(e)) - logger.error(f"{error_msg}: {e}") - raise - else: - try: - return await operation() - except Exception as e: - logger.error(f"{error_msg}: {e}") - raise - def _add_include_arg_if_present(self, args: dict[str, Any], include: dict[str, bool] | None) -> None: """Adds the 'include' argument to a dictionary if it is not None.""" if include: @@ -141,7 +100,7 @@ def _build_find_args( skip: int | None = None, cursor: dict[str, Any] | None = None, ) -> dict[str, Any]: - """Constructs the keyword arguments dictionary for Prisma find operations.""" + """Constructs the keyword arguments dictionary for SQLModel find operations.""" args: dict[str, Any] = {"where": where} self._add_include_arg_if_present(args, include) if order: @@ -160,7 +119,7 @@ def _build_simple_args( key_value: dict[str, Any], include: dict[str, bool] | None = None, ) -> dict[str, Any]: - """Constructs simple keyword arguments for Prisma (e.g., create, delete).""" + """Constructs simple keyword arguments for SQLModel (e.g., create, delete).""" args = {key_name: key_value} self._add_include_arg_if_present(args, include) return args @@ -170,7 +129,7 @@ def _build_create_args( data: dict[str, Any], include: dict[str, bool] | None = None, ) -> dict[str, Any]: - """Constructs keyword arguments for Prisma create operations.""" + """Constructs keyword arguments for SQLModel create operations.""" return self._build_simple_args("data", data, include) def _build_update_args( @@ -179,7 +138,7 @@ def _build_update_args( data: dict[str, Any], include: dict[str, bool] | None = None, ) -> dict[str, Any]: - """Constructs keyword arguments for Prisma update operations.""" + """Constructs keyword arguments for SQLModel update operations.""" args = {"where": where, "data": data} self._add_include_arg_if_present(args, include) return args @@ -189,7 +148,7 @@ def _build_delete_args( where: dict[str, Any], include: dict[str, bool] | None = None, ) -> dict[str, Any]: - """Constructs keyword arguments for Prisma delete operations.""" + """Constructs keyword arguments for SQLModel delete operations.""" return self._build_simple_args("where", where, include) def _build_upsert_args( @@ -199,7 +158,7 @@ def _build_upsert_args( update: dict[str, Any], include: dict[str, bool] | None = None, ) -> dict[str, Any]: - """Constructs keyword arguments for Prisma upsert operations.""" + """Constructs keyword arguments for SQLModel upsert operations.""" args = { "where": where, "data": { @@ -218,27 +177,15 @@ async def find_one( include: dict[str, bool] | None = None, order: dict[str, str] | None = None, ) -> ModelType | None: - """Finds the first record matching specified criteria. - - Parameters - ---------- - where : dict[str, Any] - Query conditions to match. - include : dict[str, bool], optional - Specifies relations to include in the result. - order : dict[str, str], optional - Specifies the field and direction for ordering. - - Returns - ------- - ModelType | None - The found record or None if no match exists. - """ - find_args = self._build_find_args(where=where, include=include, order=order) - return await self._execute_query( - lambda: self.table.find_first(**find_args), - f"Failed to find record in {self.table_name} with criteria {where}", - ) + """Find the first matching record using SQLModel select().""" + stmt = select(self.table).filter_by(**where) + if order: + for field, direction in order.items(): + col = getattr(self.table, field) + stmt = stmt.order_by(col.asc() if direction == "asc" else col.desc()) + stmt = stmt.limit(1) + result = await self.session.execute(stmt) + return result.scalars().first() async def find_unique( self, @@ -259,11 +206,9 @@ async def find_unique( ModelType | None The found record or None if no match exists. """ - find_args = self._build_find_args(where=where, include=include) # Order not applicable for find_unique - return await self._execute_query( - lambda: self.table.find_unique(**find_args), - f"Failed to find unique record in {self.table_name} with criteria {where}", - ) + stmt = select(self.table).filter_by(**where) + result = await self.session.execute(stmt) + return result.scalars().first() async def find_many( self, @@ -296,18 +241,17 @@ async def find_many( list[ModelType] A list of found records, potentially empty. """ - find_args = self._build_find_args( - where=where, - include=include, - order=order, - take=take, - skip=skip, - cursor=cursor, - ) - return await self._execute_query( - lambda: self.table.find_many(**find_args), - f"Failed to find records in {self.table_name} with criteria {where}", - ) + stmt = select(self.table).filter_by(**where) + if order: + for field, direction in order.items(): + col = getattr(self.table, field) + stmt = stmt.order_by(col.asc() if direction == "asc" else col.desc()) + if skip: + stmt = stmt.offset(skip) + if take: + stmt = stmt.limit(take) + result = await self.session.execute(stmt) + return list(result.scalars().all()) async def count( self, @@ -325,10 +269,9 @@ async def count( int The total number of matching records. """ - return await self._execute_query( - lambda: self.table.count(where=where), - f"Failed to count records in {self.table_name} with criteria {where}", - ) + stmt = select(func.count()).select_from(self.table).filter_by(**where) + result = await self.session.execute(stmt) + return result.scalar_one() async def create( self, @@ -349,11 +292,11 @@ async def create( ModelType The newly created record. """ - create_args = self._build_create_args(data=data, include=include) - return await self._execute_query( - lambda: self.table.create(**create_args), - f"Failed to create record in {self.table_name} with data {data}", - ) + instance = self.table(**data) + self.session.add(instance) + await self.session.commit() + await self.session.refresh(instance) + return instance async def update( self, @@ -377,11 +320,15 @@ async def update( ModelType | None The updated record, or None if no matching record was found. """ - update_args = self._build_update_args(where=where, data=data, include=include) - return await self._execute_query( - lambda: self.table.update(**update_args), - f"Failed to update record in {self.table_name} with criteria {where} and data {data}", - ) + instance = await self.find_unique(where) + if not instance: + return None + for key, value in data.items(): + setattr(instance, key, value) + self.session.add(instance) + await self.session.commit() + await self.session.refresh(instance) + return instance async def delete( self, @@ -402,11 +349,12 @@ async def delete( ModelType | None The deleted record, or None if no matching record was found. """ - delete_args = self._build_delete_args(where=where, include=include) - return await self._execute_query( - lambda: self.table.delete(**delete_args), - f"Failed to delete record in {self.table_name} with criteria {where}", - ) + instance = await self.find_unique(where) + if not instance: + return None + await self.session.delete(instance) + await self.session.commit() + return instance async def upsert( self, @@ -433,11 +381,16 @@ async def upsert( ModelType The created or updated record. """ - upsert_args = self._build_upsert_args(where=where, create=create, update=update, include=include) - return await self._execute_query( - lambda: self.table.upsert(**upsert_args), - f"Failed to upsert record in {self.table_name} with where={where}, create={create}, update={update}", - ) + instance = await self.find_unique(where) + if instance: + for key, value in update.items(): + setattr(instance, key, value) + else: + instance = self.table(**create) + self.session.add(instance) + await self.session.commit() + await self.session.refresh(instance) + return instance async def update_many( self, @@ -463,16 +416,10 @@ async def update_many( ValueError If the database operation does not return a valid count. """ - result = await self._execute_query( - lambda: self.table.update_many(where=where, data=data), - f"Failed to update records in {self.table_name} with criteria {where} and data {data}", - ) - # Validate and return count - count_val = getattr(result, "count", None) - if count_val is None or not isinstance(count_val, int): - msg = f"Update operation for {self.table_name} did not return a valid count, got: {count_val}" - raise ValueError(msg) - return count_val + stmt = sa_update(self.table).filter_by(**where).values(**data) + result = await self.session.execute(stmt) + await self.session.commit() + return result.rowcount async def delete_many( self, @@ -495,16 +442,10 @@ async def delete_many( ValueError If the database operation does not return a valid count. """ - result = await self._execute_query( - lambda: self.table.delete_many(where=where), - f"Failed to delete records in {self.table_name} with criteria {where}", - ) - # Validate and return count - count_val = getattr(result, "count", None) - if count_val is None or not isinstance(count_val, int): - msg = f"Delete operation for {self.table_name} did not return a valid count, got: {count_val}" - raise ValueError(msg) - return count_val + stmt = sa_delete(self.table).filter_by(**where) + result = await self.session.execute(stmt) + await self.session.commit() + return result.rowcount # --- Other Utility Methods --- @@ -531,10 +472,10 @@ async def execute_transaction(self, callback: Callable[[], Any]) -> Any: Re-raises any exception that occurs during the transaction. """ try: - async with db.transaction(): + async with self.session.begin(): return await callback() except Exception as e: - logger.error(f"Transaction failed in {self.table_name}: {e}") + logger.exception(f"Transaction failed in {self.table}: {e}") raise @staticmethod @@ -543,7 +484,7 @@ def connect_or_create_relation( model_id: Any, create_data: dict[str, Any] | None = None, ) -> dict[str, Any]: - """Builds a Prisma 'connect_or_create' relation structure. + """Builds a SQLModel 'connect_or_create' relation structure. Simplifies linking or creating related records during create/update operations. @@ -560,7 +501,7 @@ def connect_or_create_relation( Returns ------- dict[str, Any] - A dictionary formatted for Prisma's connect_or_create. + A dictionary formatted for SQLModel's connect_or_create. """ where = {id_field: model_id} # Create data must contain the ID field for the new record From b731cb5cfabf1ea3614da59699b229f17e614221 Mon Sep 17 00:00:00 2001 From: eden Date: Sun, 22 Jun 2025 20:38:43 -0400 Subject: [PATCH 14/17] feat(db): added alembic --- poetry.lock | 83 +++++++++++++++++++++++++++++++++++++------------- pyproject.toml | 1 + 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 23aa91d1..b15a9d02 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. [[package]] name = "aiocache" @@ -179,6 +179,26 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "alembic" +version = "1.16.2" +description = "A database migration tool for SQLAlchemy." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "alembic-1.16.2-py3-none-any.whl", hash = "sha256:5f42e9bd0afdbd1d5e3ad856c01754530367debdebf21ed6894e34af52b3bb03"}, + {file = "alembic-1.16.2.tar.gz", hash = "sha256:e53c38ff88dadb92eb22f8b150708367db731d58ad7e9d417c9168ab516cbed8"}, +] + +[package.dependencies] +Mako = "*" +SQLAlchemy = ">=1.4.0" +typing-extensions = ">=4.12" + +[package.extras] +tz = ["tzdata"] + [[package]] name = "annotated-types" version = "0.7.0" @@ -391,18 +411,19 @@ dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)" [[package]] name = "backrefs" -version = "5.8" +version = "5.9" description = "A wrapper around re and regex that adds additional back references." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "backrefs-5.8-py310-none-any.whl", hash = "sha256:c67f6638a34a5b8730812f5101376f9d41dc38c43f1fdc35cb54700f6ed4465d"}, - {file = "backrefs-5.8-py311-none-any.whl", hash = "sha256:2e1c15e4af0e12e45c8701bd5da0902d326b2e200cafcd25e49d9f06d44bb61b"}, - {file = "backrefs-5.8-py312-none-any.whl", hash = "sha256:bbef7169a33811080d67cdf1538c8289f76f0942ff971222a16034da88a73486"}, - {file = "backrefs-5.8-py313-none-any.whl", hash = "sha256:e3a63b073867dbefd0536425f43db618578528e3896fb77be7141328642a1585"}, - {file = "backrefs-5.8-py39-none-any.whl", hash = "sha256:a66851e4533fb5b371aa0628e1fee1af05135616b86140c9d787a2ffdf4b8fdc"}, - {file = "backrefs-5.8.tar.gz", hash = "sha256:2cab642a205ce966af3dd4b38ee36009b31fa9502a35fd61d59ccc116e40a6bd"}, + {file = "backrefs-5.9-py310-none-any.whl", hash = "sha256:db8e8ba0e9de81fcd635f440deab5ae5f2591b54ac1ebe0550a2ca063488cd9f"}, + {file = "backrefs-5.9-py311-none-any.whl", hash = "sha256:6907635edebbe9b2dc3de3a2befff44d74f30a4562adbb8b36f21252ea19c5cf"}, + {file = "backrefs-5.9-py312-none-any.whl", hash = "sha256:7fdf9771f63e6028d7fee7e0c497c81abda597ea45d6b8f89e8ad76994f5befa"}, + {file = "backrefs-5.9-py313-none-any.whl", hash = "sha256:cc37b19fa219e93ff825ed1fed8879e47b4d89aa7a1884860e2db64ccd7c676b"}, + {file = "backrefs-5.9-py314-none-any.whl", hash = "sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9"}, + {file = "backrefs-5.9-py39-none-any.whl", hash = "sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60"}, + {file = "backrefs-5.9.tar.gz", hash = "sha256:808548cb708d66b82ee231f962cb36faaf4f2baab032f2fbb783e9c2fdddaa59"}, ] [package.extras] @@ -1730,18 +1751,18 @@ test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-c [[package]] name = "jaraco-functools" -version = "4.1.0" +version = "4.2.1" description = "Functools like those found in stdlib" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"}, - {file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"}, + {file = "jaraco_functools-4.2.1-py3-none-any.whl", hash = "sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e"}, + {file = "jaraco_functools-4.2.1.tar.gz", hash = "sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353"}, ] [package.dependencies] -more-itertools = "*" +more_itertools = "*" [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] @@ -1996,6 +2017,26 @@ files = [ click = ">=8.0.1,<9.0.0" toml = ">=0.10.2,<0.11.0" +[[package]] +name = "mako" +version = "1.3.10" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"}, + {file = "mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + [[package]] name = "markdown" version = "3.8.2" @@ -3177,14 +3218,14 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["main", "docs", "test"] files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -3213,14 +3254,14 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymdown-extensions" -version = "10.15" +version = "10.16" description = "Extension pack for Python Markdown." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "pymdown_extensions-10.15-py3-none-any.whl", hash = "sha256:46e99bb272612b0de3b7e7caf6da8dd5f4ca5212c0b273feb9304e236c484e5f"}, - {file = "pymdown_extensions-10.15.tar.gz", hash = "sha256:0e5994e32155f4b03504f939e501b981d306daf7ec2aa1cd2eb6bd300784f8f7"}, + {file = "pymdown_extensions-10.16-py3-none-any.whl", hash = "sha256:f5dd064a4db588cb2d95229fc4ee63a1b16cc8b4d0e6145c0899ed8723da1df2"}, + {file = "pymdown_extensions-10.16.tar.gz", hash = "sha256:71dac4fca63fabeffd3eb9038b756161a33ec6e8d230853d3cecf562155ab3de"}, ] [package.dependencies] @@ -5011,4 +5052,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "a9aa2a662ee924e16bb787b90c1913537776865380fa2856ae159ef89791b941" +content-hash = "eb9a12f42f842d869e4f135cf4c60c45552e2f0e068760bf64f279f42b4f3fdc" diff --git a/pyproject.toml b/pyproject.toml index a595f4c9..100931ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ levenshtein = "^0.27.1" jinja2 = "^3.1.6" sqlmodel = "^0.0.24" asyncpg = "^0.30.0" +alembic = "^1.16.2" [tool.poetry.group.dev.dependencies] pre-commit = "==4.2.0" From 70920697c90589c17ebfedfe24147187f6c7f906 Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Sun, 6 Jul 2025 16:07:18 -0500 Subject: [PATCH 15/17] fix(controllers): continue controller migration fix(.env.example): fix comment being in wrong location fix: find/replace prisma.model calls --- .env.example | 2 +- tests/unit/tux/utils/test_exceptions.py | 2 +- tux/cogs/moderation/cases.py | 6 +- tux/cogs/moderation/tempban.py | 4 +- tux/cogs/moderation/unjail.py | 4 +- tux/cogs/snippets/__init__.py | 3 +- tux/cogs/snippets/list_snippets.py | 2 +- tux/cogs/utility/afk.py | 2 +- tux/cogs/utility/remindme.py | 2 +- tux/database/controllers/afk.py | 8 +- tux/database/controllers/base.py | 7 +- tux/database/controllers/case.py | 25 +- tux/database/controllers/guild.py | 5 +- tux/database/controllers/guild_config.py | 470 ++++++----------------- tux/database/controllers/levels.py | 8 +- tux/database/controllers/note.py | 9 +- tux/database/controllers/reminder.py | 9 +- tux/database/controllers/snippet.py | 8 +- tux/database/controllers/starboard.py | 13 +- tux/utils/exceptions.py | 2 +- 20 files changed, 161 insertions(+), 430 deletions(-) diff --git a/.env.example b/.env.example index 3d880a71..c009f901 100644 --- a/.env.example +++ b/.env.example @@ -10,13 +10,13 @@ # Database URLs (Required: one depending on mode) # The application uses DEV_DATABASE_URL when run with '--dev' flag, # and PROD_DATABASE_URL otherwise (production mode). +# PREFIX SHOULD BE postgresql+asyncpg://" DEV_DATABASE_URL="" PROD_DATABASE_URL="" # Bot Tokens (Required: one depending on mode) # The application uses DEV_BOT_TOKEN when run with '--dev' flag, # and PROD_BOT_TOKEN otherwise (production mode). -# PREFIX SHOULD BE postgresql+asyncpg:// DEV_BOT_TOKEN="" PROD_BOT_TOKEN="" diff --git a/tests/unit/tux/utils/test_exceptions.py b/tests/unit/tux/utils/test_exceptions.py index 67c606a9..10c87e47 100644 --- a/tests/unit/tux/utils/test_exceptions.py +++ b/tests/unit/tux/utils/test_exceptions.py @@ -4,8 +4,8 @@ from unittest.mock import Mock import pytest -from prisma.models import Case +from tux.database.schemas import Case from tux.utils.exceptions import ( APIConnectionError, APIRequestError, diff --git a/tux/cogs/moderation/cases.py b/tux/cogs/moderation/cases.py index 573aba5e..15ad3b07 100644 --- a/tux/cogs/moderation/cases.py +++ b/tux/cogs/moderation/cases.py @@ -3,12 +3,12 @@ import discord from discord.ext import commands from loguru import logger -from prisma.enums import CaseType -from prisma.models import Case -from prisma.types import CaseWhereInput from reactionmenu import ViewButton, ViewMenu +from prisma.enums import CaseType +from prisma.types import CaseWhereInput from tux.bot import Tux +from tux.database.schemas import Case from tux.ui.embeds import EmbedCreator, EmbedType from tux.utils import checks from tux.utils.constants import CONST diff --git a/tux/cogs/moderation/tempban.py b/tux/cogs/moderation/tempban.py index a0fa04ba..747c2e1f 100644 --- a/tux/cogs/moderation/tempban.py +++ b/tux/cogs/moderation/tempban.py @@ -3,10 +3,10 @@ import discord from discord.ext import commands, tasks from loguru import logger -from prisma.enums import CaseType -from prisma.models import Case +from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import Case from tux.utils import checks from tux.utils.flags import TempBanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/unjail.py b/tux/cogs/moderation/unjail.py index f0aaf679..e36b36aa 100644 --- a/tux/cogs/moderation/unjail.py +++ b/tux/cogs/moderation/unjail.py @@ -3,10 +3,10 @@ import discord from discord.ext import commands from loguru import logger -from prisma.enums import CaseType -from prisma.models import Case +from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import Case from tux.utils import checks from tux.utils.flags import UnjailFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/snippets/__init__.py b/tux/cogs/snippets/__init__.py index 4ca02c62..1c5c20bc 100644 --- a/tux/cogs/snippets/__init__.py +++ b/tux/cogs/snippets/__init__.py @@ -1,11 +1,10 @@ import discord from discord.ext import commands from loguru import logger -from prisma.enums import CaseType -from prisma.models import Snippet from tux.bot import Tux from tux.database.controllers import DatabaseController +from tux.database.schemas import CaseType, Snippet from tux.ui.embeds import EmbedCreator, EmbedType from tux.utils import checks from tux.utils.config import Config diff --git a/tux/cogs/snippets/list_snippets.py b/tux/cogs/snippets/list_snippets.py index ec958ee7..9cb423c4 100644 --- a/tux/cogs/snippets/list_snippets.py +++ b/tux/cogs/snippets/list_snippets.py @@ -1,8 +1,8 @@ from discord.ext import commands -from prisma.models import Snippet from reactionmenu import ViewButton, ViewMenu from tux.bot import Tux +from tux.database.schemas import Snippet from tux.utils.constants import CONST from tux.utils.functions import generate_usage diff --git a/tux/cogs/utility/afk.py b/tux/cogs/utility/afk.py index ca7f9dd8..78b85f09 100644 --- a/tux/cogs/utility/afk.py +++ b/tux/cogs/utility/afk.py @@ -6,11 +6,11 @@ import discord from discord.ext import commands, tasks -from prisma.models import AFKModel from tux.bot import Tux from tux.cogs.utility import add_afk, del_afk from tux.database.controllers import DatabaseController +from tux.database.schemas import AFKModel from tux.utils.functions import generate_usage # TODO: add `afk until` command, or add support for providing a timeframe in the regular `afk` and `permafk` commands diff --git a/tux/cogs/utility/remindme.py b/tux/cogs/utility/remindme.py index f42f35fe..38a305e3 100644 --- a/tux/cogs/utility/remindme.py +++ b/tux/cogs/utility/remindme.py @@ -4,10 +4,10 @@ import discord from discord.ext import commands, tasks from loguru import logger -from prisma.models import Reminder from tux.bot import Tux from tux.database.controllers import DatabaseController +from tux.database.schemas import Reminder from tux.ui.embeds import EmbedCreator from tux.utils.functions import convert_to_seconds, generate_usage diff --git a/tux/database/controllers/afk.py b/tux/database/controllers/afk.py index c169f22e..5febe867 100644 --- a/tux/database/controllers/afk.py +++ b/tux/database/controllers/afk.py @@ -1,10 +1,7 @@ from datetime import UTC, datetime -from prisma.actions import GuildActions -from prisma.models import AFKModel, Guild - -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import AFKModel class AfkController(BaseController[AFKModel]): @@ -16,8 +13,7 @@ class AfkController(BaseController[AFKModel]): def __init__(self) -> None: """Initialize the AfkController with the afkmodel table.""" - super().__init__("afkmodel") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(AFKModel) async def get_afk_member(self, member_id: int, *, guild_id: int) -> AFKModel | None: """Get the AFK record for a member in a guild. diff --git a/tux/database/controllers/base.py b/tux/database/controllers/base.py index a147a8e8..9f8358ab 100644 --- a/tux/database/controllers/base.py +++ b/tux/database/controllers/base.py @@ -75,11 +75,10 @@ def __init__(self, table: type[ModelType], session: AsyncSession | None = None) Parameters ---------- + table : type[ModelType] + The SQLModel model class representing the table. session : AsyncSession, optional - An optional SQLAlchemy AsyncSession instance. If not provided, - the default session from the database client will be used. - table_name : str - The name of the table this controller will manage, used for logging and error messages. + An optional SQLAlchemy async session to use for database operations. """ self.session = session or db.get_session() self.table = table diff --git a/tux/database/controllers/case.py b/tux/database/controllers/case.py index 1fe5b742..289fe2a1 100644 --- a/tux/database/controllers/case.py +++ b/tux/database/controllers/case.py @@ -1,13 +1,8 @@ from datetime import UTC, datetime from typing import Any -from prisma.actions import GuildActions -from prisma.enums import CaseType -from prisma.models import Case, Guild -from prisma.types import CaseWhereInput - -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import Case, CaseType, Guild class CaseController(BaseController[Case]): @@ -19,9 +14,8 @@ class CaseController(BaseController[Case]): def __init__(self): """Initialize the CaseController with the case table.""" - super().__init__("case") - # Access guild table through client property - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(Case) + self.guild_table = BaseController(Guild) async def get_next_case_number(self, guild_id: int) -> int: """Get the next case number for a guild. @@ -42,10 +36,8 @@ async def get_next_case_number(self, guild_id: int) -> int: # Use connect_or_create to ensure guild exists and increment case count guild = await self.guild_table.upsert( where={"guild_id": guild_id}, - data={ - "create": {"guild_id": guild_id, "case_count": 1}, - "update": {"case_count": {"increment": 1}}, - }, + create={"guild_id": guild_id, "case_count": 1}, + update={"case_count": {"increment": 1}}, ) return self.safe_get_attr(guild, "case_count", 1) @@ -147,7 +139,7 @@ async def get_all_cases(self, guild_id: int) -> list[Case]: async def get_cases_by_options( self, guild_id: int, - options: CaseWhereInput, + options: dict[str, Any], ) -> list[Case]: """Get cases for a guild by options. @@ -163,7 +155,10 @@ async def get_cases_by_options( list[Case] A list of cases for the guild matching the criteria. """ - return await self.find_many(where={"guild_id": guild_id, **options}, order={"case_created_at": "desc"}) + return await self.find_many( + where={"guild_id": guild_id, **options}, + order={"case_created_at": "desc"}, + ) async def get_case_by_number(self, guild_id: int, case_number: int, include_guild: bool = False) -> Case | None: """Get a case by its number in a guild. diff --git a/tux/database/controllers/guild.py b/tux/database/controllers/guild.py index 6ee29e26..f65e2fd7 100644 --- a/tux/database/controllers/guild.py +++ b/tux/database/controllers/guild.py @@ -1,8 +1,7 @@ from typing import Any -from prisma.models import Guild - from tux.database.controllers.base import BaseController +from tux.database.schemas import Guild class GuildController(BaseController[Guild]): @@ -14,7 +13,7 @@ class GuildController(BaseController[Guild]): def __init__(self): """Initialize the GuildController with the guild table.""" - super().__init__("guild") + super().__init__(Guild) # Type hint for better IDE support self.table: Any = self.table diff --git a/tux/database/controllers/guild_config.py b/tux/database/controllers/guild_config.py index a9b03928..6af22f2e 100644 --- a/tux/database/controllers/guild_config.py +++ b/tux/database/controllers/guild_config.py @@ -1,45 +1,42 @@ from typing import Any from loguru import logger -from prisma.actions import GuildActions, GuildConfigActions -from prisma.models import Guild, GuildConfig -from prisma.types import ( - GuildConfigScalarFieldKeys, - GuildConfigUpdateInput, -) - -from tux.database.client import db - - -class GuildConfigController: - def __init__(self): - """Initialize the controller with database tables.""" - self.table: GuildConfigActions[GuildConfig] = db.client.guildconfig - self.guild_table: GuildActions[Guild] = db.client.guild - - async def ensure_guild_exists(self, guild_id: int) -> Any: - """Ensure the guild exists in the database.""" - guild: Any = await self.guild_table.find_first(where={"guild_id": guild_id}) - if guild is None: - return await self.guild_table.create(data={"guild_id": guild_id}) - return guild - - async def insert_guild_config(self, guild_id: int) -> Any: - """Insert a new guild config into the database.""" - await self.ensure_guild_exists(guild_id) - return await self.table.create(data={"guild_id": guild_id}) - - async def get_guild_config(self, guild_id: int) -> Any: - """Get a guild config from the database.""" - return await self.table.find_first(where={"guild_id": guild_id}) + +from tux.database.controllers.base import BaseController +from tux.database.schemas import GuildConfig + + +class GuildConfigController(BaseController[GuildConfig]): + """Controller for managing GuildConfig records.""" + + def __init__(self) -> None: + super().__init__(GuildConfig) + + # --- Generic Field Reader --- + + async def get_field(self, guild_id: int, field: str) -> Any: + """ + Fetch a single scalar field from GuildConfig. + Returns None if the record or field does not exist. + """ + cfg = await self.find_unique(where={"guild_id": guild_id}) + if cfg is None: + logger.warning(f"No GuildConfig found for guild_id={guild_id}") + return None + value = self.safe_get_attr(cfg, field, None) + logger.debug(f"GuildConfig[{guild_id}].{field} = {value!r}") + return value + + # --- Read Methods --- + + async def get_guild_config(self, guild_id: int) -> GuildConfig | None: + return await self.find_unique(where={"guild_id": guild_id}) async def get_guild_prefix(self, guild_id: int) -> str | None: - """Get a guild prefix from the database.""" - config: Any = await self.table.find_first(where={"guild_id": guild_id}) - return None if config is None else config.prefix + return await self.get_field(guild_id, "prefix") async def get_log_channel(self, guild_id: int, log_type: str) -> int | None: - log_channel_ids: dict[str, GuildConfigScalarFieldKeys] = { + log_fields: dict[str, str] = { "mod": "mod_log_id", "audit": "audit_log_id", "join": "join_log_id", @@ -47,390 +44,151 @@ async def get_log_channel(self, guild_id: int, log_type: str) -> int | None: "report": "report_log_id", "dev": "dev_log_id", } - return await self.get_guild_config_field_value(guild_id, log_channel_ids[log_type]) + field = log_fields.get(log_type) + if field is None: + logger.error(f"Unknown log_type '{log_type}'") + return None + return await self.get_field(guild_id, field) - async def get_perm_level_role(self, guild_id: int, level: str) -> int | None: + async def get_perm_level_role(self, guild_id: int, level: int) -> int | None: """ Get the role id for a specific permission level. """ + field = f"perm_level_{level}_role_id" try: - role_id = await self.get_guild_config_field_value(guild_id, level) # type: ignore - logger.debug(f"Retrieved role_id {role_id} for guild {guild_id} and level {level}") + return await self.get_field(guild_id, field) except Exception as e: - logger.error(f"Error getting perm level role: {e}") + logger.error(f"Error getting perm level role {level} for guild {guild_id}: {e}") return None - return role_id async def get_perm_level_roles(self, guild_id: int, lower_bound: int) -> list[int] | None: """ - Get the role ids for all permission levels from the lower_bound up to but not including 8. + Get the role ids for all permission levels from lower_bound up to 7. """ - perm_level_roles: dict[int, str] = { - 0: "perm_level_0_role_id", - 1: "perm_level_1_role_id", - 2: "perm_level_2_role_id", - 3: "perm_level_3_role_id", - 4: "perm_level_4_role_id", - 5: "perm_level_5_role_id", - 6: "perm_level_6_role_id", - 7: "perm_level_7_role_id", - } - try: role_ids: list[int] = [] - - for level in range(lower_bound, 8): - if role_field := perm_level_roles.get(level): - role_id = await self.get_guild_config_field_value(guild_id, role_field) # type: ignore - - if role_id: - role_ids.append(role_id) - - logger.debug(f"Retrieved role_ids {role_ids} for guild {guild_id} with lower bound {lower_bound}") - + for lvl in range(lower_bound, 8): + field = f"perm_level_{lvl}_role_id" + rid = await self.get_field(guild_id, field) + if rid is not None: + role_ids.append(rid) + logger.debug(f"Retrieved perm roles >={lower_bound} for guild {guild_id}: {role_ids}") except Exception as e: - logger.error(f"Error getting perm level roles: {e}") - return None - - return role_ids - - async def get_guild_config_field_value( - self, - guild_id: int, - field: GuildConfigScalarFieldKeys, - ) -> Any: - config: Any = await self.table.find_first(where={"guild_id": guild_id}) - - if config is None: - logger.warning(f"No guild config found for guild_id: {guild_id}") + logger.error(f"Error getting perm level roles for guild {guild_id}: {e}") return None - - value = getattr(config, field, None) - - logger.debug(f"Retrieved field value for {field}: {value}") - - return value + else: + return role_ids async def get_mod_log_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "mod_log_id") + return await self.get_field(guild_id, "mod_log_id") async def get_audit_log_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "audit_log_id") + return await self.get_field(guild_id, "audit_log_id") async def get_join_log_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "join_log_id") + return await self.get_field(guild_id, "join_log_id") async def get_private_log_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "private_log_id") + return await self.get_field(guild_id, "private_log_id") async def get_report_log_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "report_log_id") + return await self.get_field(guild_id, "report_log_id") async def get_dev_log_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "dev_log_id") + return await self.get_field(guild_id, "dev_log_id") async def get_jail_channel_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "jail_channel_id") + return await self.get_field(guild_id, "jail_channel_id") async def get_general_channel_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "general_channel_id") + return await self.get_field(guild_id, "general_channel_id") async def get_starboard_channel_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "starboard_channel_id") + return await self.get_field(guild_id, "starboard_channel_id") async def get_base_staff_role_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "base_staff_role_id") + return await self.get_field(guild_id, "base_staff_role_id") async def get_base_member_role_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "base_member_role_id") + return await self.get_field(guild_id, "base_member_role_id") async def get_jail_role_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "jail_role_id") + return await self.get_field(guild_id, "jail_role_id") async def get_quarantine_role_id(self, guild_id: int) -> int | None: - return await self.get_guild_config_field_value(guild_id, "quarantine_role_id") - - async def update_guild_prefix( - self, - guild_id: int, - prefix: str, - ) -> Any: - await self.ensure_guild_exists(guild_id) - - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": {"guild_id": guild_id, "prefix": prefix}, - "update": {"prefix": prefix}, - }, - ) - - async def update_perm_level_role( - self, - guild_id: int, - level: str, - role_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) - - perm_level_roles: dict[str, str] = { - "0": "perm_level_0_role_id", - "1": "perm_level_1_role_id", - "2": "perm_level_2_role_id", - "3": "perm_level_3_role_id", - "4": "perm_level_4_role_id", - "5": "perm_level_5_role_id", - "6": "perm_level_6_role_id", - "7": "perm_level_7_role_id", - } - - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": {"guild_id": guild_id, perm_level_roles[level]: role_id}, # type: ignore - "update": {perm_level_roles[level]: role_id}, - }, - ) - - async def update_mod_log_id( - self, - guild_id: int, - mod_log_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) - - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "mod_log_id": mod_log_id, - }, - "update": {"mod_log_id": mod_log_id}, - }, - ) - - async def update_audit_log_id( - self, - guild_id: int, - audit_log_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) - - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "audit_log_id": audit_log_id, - }, - "update": {"audit_log_id": audit_log_id}, - }, - ) - - async def update_join_log_id( - self, - guild_id: int, - join_log_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) - - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "join_log_id": join_log_id, - }, - "update": {"join_log_id": join_log_id}, - }, - ) + return await self.get_field(guild_id, "quarantine_role_id") - async def update_private_log_id( - self, - guild_id: int, - private_log_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + # --- Generic Field Upserter --- - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "private_log_id": private_log_id, - }, - "update": {"private_log_id": private_log_id}, - }, - ) - - async def update_report_log_id( - self, - guild_id: int, - report_log_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) - - return await self.table.upsert( + async def _upsert_field(self, guild_id: int, field: str, value: Any) -> GuildConfig: + """ + Upsert a single scalar field on GuildConfig, ensuring the + GuildConfig row (and its guild relation) exists. + """ + return await self.upsert( where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "report_log_id": report_log_id, - }, - "update": {"report_log_id": report_log_id}, + create={ + field: value, + "guild": self.connect_or_create_relation("guild_id", guild_id), }, + update={field: value}, ) - async def update_dev_log_id( - self, - guild_id: int, - dev_log_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + # --- Write Methods --- - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "dev_log_id": dev_log_id, - }, - "update": {"dev_log_id": dev_log_id}, - }, - ) + async def update_guild_prefix(self, guild_id: int, prefix: str) -> GuildConfig: + return await self._upsert_field(guild_id, "prefix", prefix) - async def update_jail_channel_id( - self, - guild_id: int, - jail_channel_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_mod_log_id(self, guild_id: int, channel_id: int) -> GuildConfig: + return await self._upsert_field(guild_id, "mod_log_id", channel_id) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": {"guild_id": guild_id, "jail_channel_id": jail_channel_id}, - "update": {"jail_channel_id": jail_channel_id}, - }, - ) + async def update_audit_log_id(self, guild_id: int, channel_id: int) -> GuildConfig: + return await self._upsert_field(guild_id, "audit_log_id", channel_id) - async def update_general_channel_id( - self, - guild_id: int, - general_channel_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_join_log_id(self, guild_id: int, channel_id: int) -> GuildConfig: + return await self._upsert_field(guild_id, "join_log_id", channel_id) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "general_channel_id": general_channel_id, - }, - "update": {"general_channel_id": general_channel_id}, - }, - ) + async def update_private_log_id(self, guild_id: int, channel_id: int) -> GuildConfig: + return await self._upsert_field(guild_id, "private_log_id", channel_id) - async def update_starboard_channel_id( - self, - guild_id: int, - starboard_channel_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_report_log_id(self, guild_id: int, channel_id: int) -> GuildConfig: + return await self._upsert_field(guild_id, "report_log_id", channel_id) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "starboard_channel_id": starboard_channel_id, - }, - "update": {"starboard_channel_id": starboard_channel_id}, - }, - ) + async def update_dev_log_id(self, guild_id: int, channel_id: int) -> GuildConfig: + return await self._upsert_field(guild_id, "dev_log_id", channel_id) - async def update_base_staff_role_id( - self, - guild_id: int, - base_staff_role_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_jail_channel_id(self, guild_id: int, cid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "jail_channel_id", cid) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "base_staff_role_id": base_staff_role_id, - }, - "update": {"base_staff_role_id": base_staff_role_id}, - }, - ) + async def update_general_channel_id(self, guild_id: int, cid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "general_channel_id", cid) - async def update_base_member_role_id( - self, - guild_id: int, - base_member_role_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_starboard_channel_id(self, guild_id: int, cid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "starboard_channel_id", cid) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "base_member_role_id": base_member_role_id, - }, - "update": {"base_member_role_id": base_member_role_id}, - }, - ) + async def update_base_staff_role_id(self, guild_id: int, rid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "base_staff_role_id", rid) - async def update_jail_role_id( - self, - guild_id: int, - jail_role_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_base_member_role_id(self, guild_id: int, rid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "base_member_role_id", rid) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": {"guild_id": guild_id, "jail_role_id": jail_role_id}, - "update": {"jail_role_id": jail_role_id}, - }, - ) + async def update_jail_role_id(self, guild_id: int, rid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "jail_role_id", rid) - async def update_quarantine_role_id( - self, - guild_id: int, - quarantine_role_id: int, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_quarantine_role_id(self, guild_id: int, rid: int) -> GuildConfig: + return await self._upsert_field(guild_id, "quarantine_role_id", rid) - return await self.table.upsert( - where={"guild_id": guild_id}, - data={ - "create": { - "guild_id": guild_id, - "quarantine_role_id": quarantine_role_id, - }, - "update": {"quarantine_role_id": quarantine_role_id}, - }, - ) + async def update_perm_level_role(self, guild_id: int, level: int, role_id: int) -> GuildConfig: + field = f"perm_level_{level}_role_id" + return await self._upsert_field(guild_id, field, role_id) - async def update_guild_config( - self, - guild_id: int, - data: GuildConfigUpdateInput, - ) -> Any: - await self.ensure_guild_exists(guild_id) + async def update_guild_config(self, guild_id: int, data: dict[str, Any]) -> GuildConfig | None: + return await self.update(where={"guild_id": guild_id}, data=data) - return await self.table.update(where={"guild_id": guild_id}, data=data) + # --- Delete Methods --- - async def delete_guild_config(self, guild_id: int) -> None: - await self.table.delete(where={"guild_id": guild_id}) + async def delete_guild_config(self, guild_id: int) -> GuildConfig | None: + return await self.delete(where={"guild_id": guild_id}) - async def delete_guild_prefix(self, guild_id: int) -> None: - await self.table.update(where={"guild_id": guild_id}, data={"prefix": None}) + async def delete_guild_prefix(self, guild_id: int) -> GuildConfig | None: + return await self.update(where={"guild_id": guild_id}, data={"prefix": None}) diff --git a/tux/database/controllers/levels.py b/tux/database/controllers/levels.py index 294e3b20..f770bb00 100644 --- a/tux/database/controllers/levels.py +++ b/tux/database/controllers/levels.py @@ -2,11 +2,9 @@ import math from loguru import logger -from prisma.actions import GuildActions -from prisma.models import Guild, Levels -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import Guild, Levels class LevelsController(BaseController[Levels]): @@ -18,8 +16,8 @@ class LevelsController(BaseController[Levels]): def __init__(self) -> None: """Initialize the LevelsController with the levels table.""" - super().__init__("levels") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(Levels) + self.guild_table = BaseController(Guild) async def get_xp(self, member_id: int, guild_id: int) -> float: """Get the XP of a member in a guild. diff --git a/tux/database/controllers/note.py b/tux/database/controllers/note.py index 1178fedb..ddf721a1 100644 --- a/tux/database/controllers/note.py +++ b/tux/database/controllers/note.py @@ -1,8 +1,5 @@ -from prisma.actions import GuildActions -from prisma.models import Guild, Note - -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import Guild, Note class NoteController(BaseController[Note]): @@ -14,8 +11,8 @@ class NoteController(BaseController[Note]): def __init__(self): """Initialize the NoteController with the note table.""" - super().__init__("note") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(Note) + self.guild_table = BaseController(Guild) async def get_all_notes(self) -> list[Note]: """Get all notes across all guilds. diff --git a/tux/database/controllers/reminder.py b/tux/database/controllers/reminder.py index fb1ca045..ee32c62c 100644 --- a/tux/database/controllers/reminder.py +++ b/tux/database/controllers/reminder.py @@ -1,10 +1,7 @@ from datetime import UTC, datetime -from prisma.actions import GuildActions -from prisma.models import Guild, Reminder - -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import Guild, Reminder class ReminderController(BaseController[Reminder]): @@ -16,8 +13,8 @@ class ReminderController(BaseController[Reminder]): def __init__(self) -> None: """Initialize the ReminderController with the reminder table.""" - super().__init__("reminder") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(Reminder) + self.guild_table = BaseController(Guild) async def get_all_reminders(self) -> list[Reminder]: """Get all reminders across all guilds. diff --git a/tux/database/controllers/snippet.py b/tux/database/controllers/snippet.py index a052c60f..8c2bce79 100644 --- a/tux/database/controllers/snippet.py +++ b/tux/database/controllers/snippet.py @@ -1,10 +1,7 @@ import datetime -from prisma.actions import GuildActions -from prisma.models import Guild, Snippet - -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import Snippet class SnippetController(BaseController[Snippet]): @@ -16,8 +13,7 @@ class SnippetController(BaseController[Snippet]): def __init__(self) -> None: """Initialize the SnippetController with the snippet table.""" - super().__init__("snippet") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(Snippet) async def get_all_snippets(self) -> list[Snippet]: """Get all snippets. diff --git a/tux/database/controllers/starboard.py b/tux/database/controllers/starboard.py index b79b0b43..b304fa39 100644 --- a/tux/database/controllers/starboard.py +++ b/tux/database/controllers/starboard.py @@ -1,10 +1,7 @@ from datetime import datetime -from prisma.actions import GuildActions -from prisma.models import Guild, Starboard, StarboardMessage - -from tux.database.client import db from tux.database.controllers.base import BaseController +from tux.database.schemas import Guild, Starboard, StarboardMessage class StarboardController(BaseController[Starboard]): @@ -16,8 +13,8 @@ class StarboardController(BaseController[Starboard]): def __init__(self): """Initialize the StarboardController with the starboard table.""" - super().__init__("starboard") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(Starboard) + self.guild_table = BaseController(Guild) async def get_all_starboards(self) -> list[Starboard]: """Get all starboards. @@ -119,8 +116,8 @@ class StarboardMessageController(BaseController[StarboardMessage]): def __init__(self): """Initialize the StarboardMessageController with the starboardmessage table.""" - super().__init__("starboardmessage") - self.guild_table: GuildActions[Guild] = db.client.guild + super().__init__(StarboardMessage) + self.guild_table = BaseController(Guild) async def get_starboard_message(self, message_id: int, guild_id: int) -> StarboardMessage | None: """Get a starboard message by message ID and guild ID. diff --git a/tux/utils/exceptions.py b/tux/utils/exceptions.py index fc910256..56d41c90 100644 --- a/tux/utils/exceptions.py +++ b/tux/utils/exceptions.py @@ -1,6 +1,6 @@ from typing import TypeVar -from prisma.models import Case +from tux.database.schemas import Case class PermissionLevelError(Exception): From 92bdf02ded754603adcbbb0fc9bf9bf6aed784f2 Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Sun, 6 Jul 2025 16:22:48 -0500 Subject: [PATCH 16/17] chore(pyproject.toml): update pillow --- poetry.lock | 197 ++++++++++++++++++++++++++++--------------------- pyproject.toml | 2 +- 2 files changed, 112 insertions(+), 87 deletions(-) diff --git a/poetry.lock b/poetry.lock index b15a9d02..7ba0b294 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "aiocache" @@ -2684,101 +2684,126 @@ install = ["zstandard (>=0.21.0)"] [[package]] name = "pillow" -version = "11.2.1" +version = "11.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047"}, - {file = "pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d"}, - {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97"}, - {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579"}, - {file = "pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d"}, - {file = "pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad"}, - {file = "pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2"}, - {file = "pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70"}, - {file = "pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788"}, - {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e"}, - {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e"}, - {file = "pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6"}, - {file = "pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193"}, - {file = "pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7"}, - {file = "pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f"}, - {file = "pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4"}, - {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443"}, - {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c"}, - {file = "pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3"}, - {file = "pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941"}, - {file = "pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb"}, - {file = "pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28"}, - {file = "pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155"}, - {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14"}, - {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b"}, - {file = "pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2"}, - {file = "pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691"}, - {file = "pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c"}, - {file = "pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22"}, - {file = "pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91"}, - {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751"}, - {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9"}, - {file = "pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd"}, - {file = "pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e"}, - {file = "pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681"}, - {file = "pillow-11.2.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:7491cf8a79b8eb867d419648fff2f83cb0b3891c8b36da92cc7f1931d46108c8"}, - {file = "pillow-11.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b02d8f9cb83c52578a0b4beadba92e37d83a4ef11570a8688bbf43f4ca50909"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:014ca0050c85003620526b0ac1ac53f56fc93af128f7546623cc8e31875ab928"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3692b68c87096ac6308296d96354eddd25f98740c9d2ab54e1549d6c8aea9d79"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f781dcb0bc9929adc77bad571b8621ecb1e4cdef86e940fe2e5b5ee24fd33b35"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2b490402c96f907a166615e9a5afacf2519e28295f157ec3a2bb9bd57de638cb"}, - {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6b20b93b3ccc9c1b597999209e4bc5cf2853f9ee66e3fc9a400a78733ffc9a"}, - {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4b835d89c08a6c2ee7781b8dd0a30209a8012b5f09c0a665b65b0eb3560b6f36"}, - {file = "pillow-11.2.1-cp39-cp39-win32.whl", hash = "sha256:b10428b3416d4f9c61f94b494681280be7686bda15898a3a9e08eb66a6d92d67"}, - {file = "pillow-11.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ebce70c3f486acf7591a3d73431fa504a4e18a9b97ff27f5f47b7368e4b9dd1"}, - {file = "pillow-11.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:c27476257b2fdcd7872d54cfd119b3a9ce4610fb85c8e32b70b42e3680a29a1e"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044"}, - {file = "pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"}, + {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"}, + {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"}, + {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"}, + {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"}, + {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"}, + {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"}, + {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"}, + {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"}, + {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"}, + {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"}, + {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"}, + {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"}, + {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"}, + {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"}, + {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"}, + {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"}, + {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"}, + {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"}, + {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"}, + {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"}, + {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"}, + {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"}, + {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"}, + {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"}, + {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] test-arrow = ["pyarrow"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] @@ -5052,4 +5077,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "eb9a12f42f842d869e4f135cf4c60c45552e2f0e068760bf64f279f42b4f3fdc" +content-hash = "0be090159f6bf795517a44df5dafb146c1f3a77f0553db3139eceb681dfa596d" diff --git a/pyproject.toml b/pyproject.toml index 100931ea..9be12881 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ githubkit = { version = ">=0.12.0", extras = ["auth-app"] } httpx = ">=0.28.0" jishaku = ">=2.5.2" loguru = ">=0.7.2" -pillow = ">=11.2.1,<11.3.0" +pillow = ">=11.3.0,<11.4.0" psutil = ">=6.0.0" pynacl = ">=1.5.0" python-dotenv = ">=1.0.1" From e9ff44e96ded292a977e2c239e4863f76d843e21 Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Mon, 14 Jul 2025 01:10:50 -0500 Subject: [PATCH 17/17] refactor(moderation): replace prisma.enums.CaseType with tux.database.schemas.CaseType --- tux/cogs/moderation/__init__.py | 2 +- tux/cogs/moderation/ban.py | 2 +- tux/cogs/moderation/cases.py | 6 ++---- tux/cogs/moderation/jail.py | 2 +- tux/cogs/moderation/kick.py | 2 +- tux/cogs/moderation/pollban.py | 2 +- tux/cogs/moderation/pollunban.py | 2 +- tux/cogs/moderation/snippetban.py | 2 +- tux/cogs/moderation/snippetunban.py | 2 +- tux/cogs/moderation/tempban.py | 3 +-- tux/cogs/moderation/timeout.py | 2 +- tux/cogs/moderation/unban.py | 2 +- tux/cogs/moderation/unjail.py | 3 +-- tux/cogs/moderation/untimeout.py | 2 +- tux/cogs/moderation/warn.py | 2 +- tux/cogs/utility/poll.py | 2 +- tux/utils/converters.py | 3 ++- tux/utils/flags.py | 2 +- 18 files changed, 20 insertions(+), 23 deletions(-) diff --git a/tux/cogs/moderation/__init__.py b/tux/cogs/moderation/__init__.py index b501c2b3..ba7fa770 100644 --- a/tux/cogs/moderation/__init__.py +++ b/tux/cogs/moderation/__init__.py @@ -7,10 +7,10 @@ import discord from discord.ext import commands from loguru import logger -from prisma.enums import CaseType from tux.bot import Tux from tux.database.controllers import DatabaseController +from tux.database.schemas import CaseType from tux.ui.embeds import EmbedCreator, EmbedType from tux.utils.constants import CONST from tux.utils.exceptions import handle_case_result, handle_gather_result diff --git a/tux/cogs/moderation/ban.py b/tux/cogs/moderation/ban.py index 2c41e1aa..46f19d15 100644 --- a/tux/cogs/moderation/ban.py +++ b/tux/cogs/moderation/ban.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import BanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/cases.py b/tux/cogs/moderation/cases.py index 15ad3b07..6d4bd7ec 100644 --- a/tux/cogs/moderation/cases.py +++ b/tux/cogs/moderation/cases.py @@ -5,10 +5,8 @@ from loguru import logger from reactionmenu import ViewButton, ViewMenu -from prisma.enums import CaseType -from prisma.types import CaseWhereInput from tux.bot import Tux -from tux.database.schemas import Case +from tux.database.schemas import Case, CaseType from tux.ui.embeds import EmbedCreator, EmbedType from tux.utils import checks from tux.utils.constants import CONST @@ -246,7 +244,7 @@ async def _view_cases_with_flags( """ assert ctx.guild - options: CaseWhereInput = {} + options: dict[str, Any] = {} if flags.type: options["case_type"] = flags.type diff --git a/tux/cogs/moderation/jail.py b/tux/cogs/moderation/jail.py index 96c98e9a..49f60a3a 100644 --- a/tux/cogs/moderation/jail.py +++ b/tux/cogs/moderation/jail.py @@ -1,9 +1,9 @@ import discord from discord.ext import commands from loguru import logger -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import JailFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/kick.py b/tux/cogs/moderation/kick.py index 90aa80c8..95c8d145 100644 --- a/tux/cogs/moderation/kick.py +++ b/tux/cogs/moderation/kick.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import KickFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/pollban.py b/tux/cogs/moderation/pollban.py index 93b6afe6..e7a6a836 100644 --- a/tux/cogs/moderation/pollban.py +++ b/tux/cogs/moderation/pollban.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import PollBanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/pollunban.py b/tux/cogs/moderation/pollunban.py index 48d2972c..ba16d6e3 100644 --- a/tux/cogs/moderation/pollunban.py +++ b/tux/cogs/moderation/pollunban.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import PollUnbanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/snippetban.py b/tux/cogs/moderation/snippetban.py index 03a152f9..0ff560bf 100644 --- a/tux/cogs/moderation/snippetban.py +++ b/tux/cogs/moderation/snippetban.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import SnippetBanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/snippetunban.py b/tux/cogs/moderation/snippetunban.py index bb3ef17d..39206b54 100644 --- a/tux/cogs/moderation/snippetunban.py +++ b/tux/cogs/moderation/snippetunban.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import SnippetUnbanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/tempban.py b/tux/cogs/moderation/tempban.py index 747c2e1f..95e4de7c 100644 --- a/tux/cogs/moderation/tempban.py +++ b/tux/cogs/moderation/tempban.py @@ -4,9 +4,8 @@ from discord.ext import commands, tasks from loguru import logger -from prisma.enums import CaseType from tux.bot import Tux -from tux.database.schemas import Case +from tux.database.schemas import Case, CaseType from tux.utils import checks from tux.utils.flags import TempBanFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/timeout.py b/tux/cogs/moderation/timeout.py index a2fbc223..80a7b2a1 100644 --- a/tux/cogs/moderation/timeout.py +++ b/tux/cogs/moderation/timeout.py @@ -2,9 +2,9 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import TimeoutFlags from tux.utils.functions import generate_usage, parse_time_string diff --git a/tux/cogs/moderation/unban.py b/tux/cogs/moderation/unban.py index bec74e87..e964dffa 100644 --- a/tux/cogs/moderation/unban.py +++ b/tux/cogs/moderation/unban.py @@ -2,9 +2,9 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.constants import CONST from tux.utils.flags import UnbanFlags diff --git a/tux/cogs/moderation/unjail.py b/tux/cogs/moderation/unjail.py index e36b36aa..2c3f594d 100644 --- a/tux/cogs/moderation/unjail.py +++ b/tux/cogs/moderation/unjail.py @@ -4,9 +4,8 @@ from discord.ext import commands from loguru import logger -from prisma.enums import CaseType from tux.bot import Tux -from tux.database.schemas import Case +from tux.database.schemas import Case, CaseType from tux.utils import checks from tux.utils.flags import UnjailFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/untimeout.py b/tux/cogs/moderation/untimeout.py index 6dedfd87..5fec141e 100644 --- a/tux/cogs/moderation/untimeout.py +++ b/tux/cogs/moderation/untimeout.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import UntimeoutFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/moderation/warn.py b/tux/cogs/moderation/warn.py index bab8b6fd..606ec356 100644 --- a/tux/cogs/moderation/warn.py +++ b/tux/cogs/moderation/warn.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from prisma.enums import CaseType from tux.bot import Tux +from tux.database.schemas import CaseType from tux.utils import checks from tux.utils.flags import WarnFlags from tux.utils.functions import generate_usage diff --git a/tux/cogs/utility/poll.py b/tux/cogs/utility/poll.py index 2d28ba04..b0a13d98 100644 --- a/tux/cogs/utility/poll.py +++ b/tux/cogs/utility/poll.py @@ -2,10 +2,10 @@ from discord import app_commands from discord.ext import commands from loguru import logger -from prisma.enums import CaseType from tux.bot import Tux from tux.database.controllers import DatabaseController +from tux.database.schemas import CaseType from tux.ui.embeds import EmbedCreator # TODO: Create option inputs for the poll command instead of using a comma separated string diff --git a/tux/utils/converters.py b/tux/utils/converters.py index 776ee4cf..386d43a1 100644 --- a/tux/utils/converters.py +++ b/tux/utils/converters.py @@ -2,7 +2,8 @@ from typing import Any from discord.ext import commands -from prisma.enums import CaseType + +from tux.database.schemas import CaseType time_regex = re.compile(r"(\d{1,5}(?:[.,]?\d{1,5})?)([smhd])") time_dict = {"h": 3600, "s": 1, "m": 60, "d": 86400} diff --git a/tux/utils/flags.py b/tux/utils/flags.py index 6cc56fa0..d226d95a 100644 --- a/tux/utils/flags.py +++ b/tux/utils/flags.py @@ -1,7 +1,7 @@ import discord from discord.ext import commands -from prisma.enums import CaseType +from tux.database.schemas import CaseType from tux.utils.constants import CONST from tux.utils.converters import CaseTypeConverter, TimeConverter, convert_bool