From d556bd3dfab85869860d44725162678c55838c1e Mon Sep 17 00:00:00 2001 From: nova Date: Mon, 19 Feb 2024 09:32:03 +0000 Subject: [PATCH 1/4] Fix typing --- src/extensions/boosts.py | 4 +--- src/extensions/user_roles.py | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/extensions/boosts.py b/src/extensions/boosts.py index b7ad3bb..b4532ad 100644 --- a/src/extensions/boosts.py +++ b/src/extensions/boosts.py @@ -27,9 +27,7 @@ def build_boost_message( assert message_type in BOOST_MESSAGE_TYPES base_message = f"{booster_user.display_name} just boosted the server" - multiple_boosts_message = ( - f" **{number_of_boosts}** times" if number_of_boosts else "" - ) + multiple_boosts_message = f" **{number_of_boosts}** times" if number_of_boosts else "" message = base_message + multiple_boosts_message + "!" diff --git a/src/extensions/user_roles.py b/src/extensions/user_roles.py index e86ef13..b7ecbc8 100644 --- a/src/extensions/user_roles.py +++ b/src/extensions/user_roles.py @@ -66,10 +66,7 @@ async def remove_role( int(role), reason=f"{ctx.author} removed role.", ) - await ctx.respond( - f"Done! Removed {role_mention(role)} from your roles.", - flags=hikari.MessageFlag.EPHEMERAL, - ) + await ctx.respond(f"Done! Removed {role_mention(role)} from your roles.", flags=hikari.MessageFlag.EPHEMERAL) @role.set_error_handler From 754a252bfeba3c7c368f27cc70389c19f74a9e07 Mon Sep 17 00:00:00 2001 From: nova Date: Thu, 22 Feb 2024 10:52:17 +0000 Subject: [PATCH 2/4] Add starboard base --- .dockerignore | 5 ++ docker-compose.yaml | 24 ++++++ src/database.py | 24 +++++- src/extensions/starboard.py | 164 ++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 docker-compose.yaml create mode 100644 src/extensions/starboard.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c2f97b7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.github/ +.ruff_cache/ +.venv/ +postgres_data/ +__pycache__/ \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..8a69253 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,24 @@ +version: "2" + +services: + bot: + build: . + depends_on: + - postgres + environment: + - POSTGRES_HOST=postgres + - POSTGRES_PORT=5432 + - POSTGRES_DB_NAME=blockbot + restart: unless-stopped + + postgres: + image: postgres:16.2-alpine3.19 + environment: + POSTGRES_DB: blockbot + PGDATA: /var/lib/postgresql/data + restart: unless-stopped + volumes: + - ./postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: \ No newline at end of file diff --git a/src/database.py b/src/database.py index 1d7a19c..7a21d1c 100644 --- a/src/database.py +++ b/src/database.py @@ -1,3 +1,4 @@ +from sqlalchemy import BigInteger, Column, Integer, SmallInteger from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from sqlalchemy.ext.declarative import declarative_base @@ -7,11 +8,30 @@ f"postgresql+asyncpg://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}", echo=False ) - Base = declarative_base() Session = async_sessionmaker(bind=engine) - async def init_db() -> None: async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) + +# TODO: add reprs? + +class StarboardSettings(Base): + __tablename__ = "starboard_settings" + + guild = Column(BigInteger, nullable=False, primary_key=True) + channel = Column(BigInteger, nullable=True) + threshold = Column(SmallInteger, nullable=False, default=3) + + +class Starboard(Base): + __tablename__ = "starboard" + + id = Column(Integer, nullable=False, primary_key=True, autoincrement=True) + channel = Column(BigInteger, nullable=False) + message = Column(BigInteger, nullable=False) + stars = Column(SmallInteger, nullable=False) + starboard_channel = Column(BigInteger, nullable=False) + starboard_message = Column(BigInteger, nullable=False) + starboard_stars = Column(SmallInteger, nullable=False) diff --git a/src/extensions/starboard.py b/src/extensions/starboard.py new file mode 100644 index 0000000..5551845 --- /dev/null +++ b/src/extensions/starboard.py @@ -0,0 +1,164 @@ +from __future__ import annotations + +import logging + +import arc +import hikari +from sqlalchemy import delete, insert, select, update +from sqlalchemy.ext.asyncio import AsyncEngine + +from src.database import Starboard, StarboardSettings + +logger = logging.getLogger(__name__) + +plugin = arc.GatewayPlugin("Starboard") + +@plugin.listen() +@plugin.inject_dependencies +async def on_reaction( + event: hikari.GuildReactionAddEvent, + session: AsyncEngine = arc.inject(), +) -> None: + logger.info("Received guild reaction add event") + + if event.emoji_name != "⭐": + return + + message = await plugin.client.rest.fetch_message(event.channel_id, event.message_id) + star_count = sum(r.emoji == "⭐" for r in message.reactions) + + stmt = select(StarboardSettings).where(StarboardSettings.guild == event.guild_id) + async with session.connect() as conn: + result = await conn.execute(stmt) + + settings = result.first() + + # TODO: remove temporary logging and merge into one if statement + if not settings: + logger.info("Received star but no guild starboard set") + return + if star_count < settings.threshold: + logger.info("Not enough stars to post to starboard") + return + if not settings.channel: + logger.info("No starboard channel set") + return + + async with session.connect() as conn: + stmt = select(Starboard).where(Starboard.message == event.message_id) + result = await conn.execute(stmt) + starboard = result.first() + + logger.info(starboard) + + if not starboard: + stmt = select(Starboard).where(Starboard.starboard_message == event.message_id) + result = await conn.execute(stmt) + starboard = result.first() + + logger.info(starboard) + + embed = hikari.Embed(description=f"⭐ {star_count}\n[link]({message.make_link(event.guild_id)})") + + # TODO: handle starring the starboard message + # i.e. don't create a starboard message for the starboard message + + if not starboard: + try: + logger.info("Creating message") + message = await plugin.client.rest.create_message( + settings.channel, + embed, + ) + stmt = insert(Starboard).values( + channel=event.channel_id, + message=event.message_id, + stars=star_count, + starboard_channel=settings.channel, + starboard_message=message.id, + starboard_stars=0, + ) + + async with session.begin() as conn: + await conn.execute(stmt) + await conn.commit() + except hikari.ForbiddenError: + logger.info("Can't access starboard channel") + stmt = update(StarboardSettings).where(StarboardSettings.guild == event.guild_id).values( + channel=None) + + async with session.begin() as conn: + await conn.execute(stmt) + await conn.commit() + + else: + try: + logger.info("Editing message") + await plugin.client.rest.edit_message( + starboard.starboard_channel, + starboard.starboard_message, + embed + ) + except hikari.ForbiddenError: + logger.info("Can't edit starboard message") + stmt = delete(StarboardSettings).where(StarboardSettings.guild == event.guild_id) + + async with session.begin() as conn: + await conn.execute(stmt) + await conn.commit() + +@plugin.include +@arc.slash_command("starboard", "Edit or view starboard settings.", default_permissions=hikari.Permissions.MANAGE_GUILD) +async def starboard_settings( + ctx: arc.GatewayContext, + channel: arc.Option[hikari.TextableGuildChannel | None, arc.ChannelParams("The channel to post starboard messages to.")] = None, + threshold: arc.Option[int | None, arc.IntParams("The minimum number of stars before this message is posted to the starboard", min=1)] = None, + session: AsyncEngine = arc.inject(), +) -> None: + assert ctx.guild_id + + stmt = select(StarboardSettings).where(StarboardSettings.guild == ctx.guild_id) + async with session.connect() as conn: + result = await conn.execute(stmt) + + settings = result.first() + + if not channel and not threshold: + if not settings: + await ctx.respond("This server has no starboard settings.", flags=hikari.MessageFlag.EPHEMERAL) + else: + # TODO: `channel` and `threshold` can be None + embed = hikari.Embed( + title="Starboard Settings", + description=( + f"**Channel:** <#{settings.channel}>\n" + f"**Threshold:** {settings.threshold}" + ), + ) + await ctx.respond(embed) + + return + + if not settings: + stmt = insert(StarboardSettings).values(guild=ctx.guild_id) + else: + stmt = update(StarboardSettings).where(StarboardSettings.guild == ctx.guild_id) + + # TODO: simplify logic + if channel and threshold: + stmt = stmt.values(channel=channel.id, threshold=threshold) + elif channel: + stmt = stmt.values(channel=channel.id) + elif threshold: + stmt = stmt.values(threshold=threshold) + + async with session.begin() as conn: + await conn.execute(stmt) + await conn.commit() + + # TODO: respond with embed of new settings? + await ctx.respond("Settings updated.", flags=hikari.MessageFlag.EPHEMERAL) + +@arc.loader +def loader(client: arc.GatewayClient) -> None: + client.add_plugin(plugin) From 8bf423ce5778089cc7ee66877ba085a5e2480acf Mon Sep 17 00:00:00 2001 From: nova Date: Wed, 15 Jan 2025 16:58:41 +0000 Subject: [PATCH 3/4] Remove dockerignore & old compose, and format code --- .dockerignore | 5 ----- docker-compose.yaml | 24 ------------------------ src/database.py | 5 ++++- src/extensions/boosts.py | 4 +++- src/extensions/user_roles.py | 5 ++++- 5 files changed, 11 insertions(+), 32 deletions(-) delete mode 100644 .dockerignore delete mode 100644 docker-compose.yaml diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index c2f97b7..0000000 --- a/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -.github/ -.ruff_cache/ -.venv/ -postgres_data/ -__pycache__/ \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 8a69253..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,24 +0,0 @@ -version: "2" - -services: - bot: - build: . - depends_on: - - postgres - environment: - - POSTGRES_HOST=postgres - - POSTGRES_PORT=5432 - - POSTGRES_DB_NAME=blockbot - restart: unless-stopped - - postgres: - image: postgres:16.2-alpine3.19 - environment: - POSTGRES_DB: blockbot - PGDATA: /var/lib/postgresql/data - restart: unless-stopped - volumes: - - ./postgres_data:/var/lib/postgresql/data - -volumes: - postgres_data: \ No newline at end of file diff --git a/src/database.py b/src/database.py index 7a21d1c..d8c3db4 100644 --- a/src/database.py +++ b/src/database.py @@ -11,19 +11,22 @@ Base = declarative_base() Session = async_sessionmaker(bind=engine) + async def init_db() -> None: async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) + # TODO: add reprs? + class StarboardSettings(Base): __tablename__ = "starboard_settings" guild = Column(BigInteger, nullable=False, primary_key=True) channel = Column(BigInteger, nullable=True) threshold = Column(SmallInteger, nullable=False, default=3) - + class Starboard(Base): __tablename__ = "starboard" diff --git a/src/extensions/boosts.py b/src/extensions/boosts.py index b4532ad..b7ad3bb 100644 --- a/src/extensions/boosts.py +++ b/src/extensions/boosts.py @@ -27,7 +27,9 @@ def build_boost_message( assert message_type in BOOST_MESSAGE_TYPES base_message = f"{booster_user.display_name} just boosted the server" - multiple_boosts_message = f" **{number_of_boosts}** times" if number_of_boosts else "" + multiple_boosts_message = ( + f" **{number_of_boosts}** times" if number_of_boosts else "" + ) message = base_message + multiple_boosts_message + "!" diff --git a/src/extensions/user_roles.py b/src/extensions/user_roles.py index b7ecbc8..e86ef13 100644 --- a/src/extensions/user_roles.py +++ b/src/extensions/user_roles.py @@ -66,7 +66,10 @@ async def remove_role( int(role), reason=f"{ctx.author} removed role.", ) - await ctx.respond(f"Done! Removed {role_mention(role)} from your roles.", flags=hikari.MessageFlag.EPHEMERAL) + await ctx.respond( + f"Done! Removed {role_mention(role)} from your roles.", + flags=hikari.MessageFlag.EPHEMERAL, + ) @role.set_error_handler From aea1ee783d93ee4cde0c9a7acc7c0831dd1e2766 Mon Sep 17 00:00:00 2001 From: nova Date: Thu, 16 Jan 2025 21:45:56 +0000 Subject: [PATCH 4/4] Update database tables and queries --- src/bot.py | 2 +- src/database.py | 34 +++-- src/extensions/starboard.py | 252 +++++++++++++++++++++++------------- 3 files changed, 182 insertions(+), 106 deletions(-) diff --git a/src/bot.py b/src/bot.py index 91edeab..4967806 100644 --- a/src/bot.py +++ b/src/bot.py @@ -59,6 +59,6 @@ async def error_handler(ctx: arc.GatewayContext, exc: Exception) -> None: raise exc -@client.set_startup_hook +@client.add_startup_hook async def startup_hook(_: arc.GatewayClient) -> None: await init_db() diff --git a/src/database.py b/src/database.py index d8c3db4..65406eb 100644 --- a/src/database.py +++ b/src/database.py @@ -1,6 +1,6 @@ -from sqlalchemy import BigInteger, Column, Integer, SmallInteger -from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import BigInteger, Integer, SmallInteger +from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, create_async_engine +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from src.config import DB_HOST, DB_NAME, DB_PASSWORD, DB_USER @@ -8,7 +8,11 @@ f"postgresql+asyncpg://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}", echo=False ) -Base = declarative_base() + +class Base(AsyncAttrs, DeclarativeBase): + pass + + Session = async_sessionmaker(bind=engine) @@ -23,18 +27,20 @@ async def init_db() -> None: class StarboardSettings(Base): __tablename__ = "starboard_settings" - guild = Column(BigInteger, nullable=False, primary_key=True) - channel = Column(BigInteger, nullable=True) - threshold = Column(SmallInteger, nullable=False, default=3) + guild_id: Mapped[int] = mapped_column(BigInteger, nullable=False, primary_key=True) + channel_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True) + threshold: Mapped[int] = mapped_column(SmallInteger, nullable=False, default=3) + error: Mapped[int | None] = mapped_column(SmallInteger, nullable=True, default=None) class Starboard(Base): __tablename__ = "starboard" - id = Column(Integer, nullable=False, primary_key=True, autoincrement=True) - channel = Column(BigInteger, nullable=False) - message = Column(BigInteger, nullable=False) - stars = Column(SmallInteger, nullable=False) - starboard_channel = Column(BigInteger, nullable=False) - starboard_message = Column(BigInteger, nullable=False) - starboard_stars = Column(SmallInteger, nullable=False) + id: Mapped[int] = mapped_column( + Integer, nullable=False, primary_key=True, autoincrement=True + ) + channel_id: Mapped[int] = mapped_column(BigInteger, nullable=False) + message_id: Mapped[int] = mapped_column(BigInteger, nullable=False) + stars: Mapped[int] = mapped_column(SmallInteger, nullable=False) + starboard_channel_id: Mapped[int] = mapped_column(BigInteger, nullable=False) + starboard_message_id: Mapped[int] = mapped_column(BigInteger, nullable=False) diff --git a/src/extensions/starboard.py b/src/extensions/starboard.py index 5551845..7918e9b 100644 --- a/src/extensions/starboard.py +++ b/src/extensions/starboard.py @@ -1,37 +1,44 @@ from __future__ import annotations +import enum import logging import arc import hikari -from sqlalchemy import delete, insert, select, update -from sqlalchemy.ext.asyncio import AsyncEngine +from sqlalchemy import insert, select, update -from src.database import Starboard, StarboardSettings +from src.database import Session, Starboard, StarboardSettings logger = logging.getLogger(__name__) plugin = arc.GatewayPlugin("Starboard") + +class StarboardSettingsError(enum.IntEnum): + CHANNEL_FORBIDDEN = 0 + CHANNEL_NOT_FOUND = 1 + + +# TODO: handle star remove @plugin.listen() -@plugin.inject_dependencies async def on_reaction( event: hikari.GuildReactionAddEvent, - session: AsyncEngine = arc.inject(), ) -> None: logger.info("Received guild reaction add event") - + if event.emoji_name != "⭐": return message = await plugin.client.rest.fetch_message(event.channel_id, event.message_id) star_count = sum(r.emoji == "⭐" for r in message.reactions) - stmt = select(StarboardSettings).where(StarboardSettings.guild == event.guild_id) - async with session.connect() as conn: - result = await conn.execute(stmt) - - settings = result.first() + # get starboard settings + async with Session() as session: + stmt = select(StarboardSettings).where( + StarboardSettings.guild_id == event.guild_id + ) + result = await session.execute(stmt) + settings = result.scalars().first() # TODO: remove temporary logging and merge into one if statement if not settings: @@ -40,125 +47,188 @@ async def on_reaction( if star_count < settings.threshold: logger.info("Not enough stars to post to starboard") return - if not settings.channel: + if not settings.channel_id: logger.info("No starboard channel set") return - - async with session.connect() as conn: - stmt = select(Starboard).where(Starboard.message == event.message_id) - result = await conn.execute(stmt) - starboard = result.first() - - logger.info(starboard) - - if not starboard: - stmt = select(Starboard).where(Starboard.starboard_message == event.message_id) - result = await conn.execute(stmt) - starboard = result.first() - - logger.info(starboard) - - embed = hikari.Embed(description=f"⭐ {star_count}\n[link]({message.make_link(event.guild_id)})") - - # TODO: handle starring the starboard message - # i.e. don't create a starboard message for the starboard message + if settings.error is not None: + logger.info("Error with starboard channel") + return - if not starboard: - try: + # TODO: consider ignoring stars reacted to a starboard message + + # get starred message + async with Session() as session: + stmt = select(Starboard).where(Starboard.message_id == event.message_id) + result = await session.execute(stmt) + starboard = result.scalars().first() + + embed = hikari.Embed( + title=f"⭐ {star_count} - *jump to message*", + url=message.make_link(event.guild_id), + description=message.content, + timestamp=message.timestamp, + ).set_author( + name=message.author.username, + icon=message.author.display_avatar_url, + ) + + images = [ + att + for att in message.attachments + if att.media_type and att.media_type.startswith("image") + ] + if images: + embed.set_image(images[0]) + + embeds = [embed, *message.embeds] + + try: + if not starboard: logger.info("Creating message") message = await plugin.client.rest.create_message( - settings.channel, - embed, - ) - stmt = insert(Starboard).values( - channel=event.channel_id, - message=event.message_id, - stars=star_count, - starboard_channel=settings.channel, - starboard_message=message.id, - starboard_stars=0, + settings.channel_id, + embeds=embeds, ) - async with session.begin() as conn: - await conn.execute(stmt) - await conn.commit() - except hikari.ForbiddenError: - logger.info("Can't access starboard channel") - stmt = update(StarboardSettings).where(StarboardSettings.guild == event.guild_id).values( - channel=None) - - async with session.begin() as conn: - await conn.execute(stmt) - await conn.commit() - - else: - try: - logger.info("Editing message") - await plugin.client.rest.edit_message( - starboard.starboard_channel, - starboard.starboard_message, - embed + async with Session() as session: + session.add( + Starboard( + channel_id=event.channel_id, + message_id=event.message_id, + stars=star_count, + starboard_channel_id=settings.channel_id, + starboard_message_id=message.id, + ) + ) + await session.commit() + else: + try: + logger.info("Editing message") + await plugin.client.rest.edit_message( + starboard.starboard_channel_id, + starboard.starboard_message_id, + embeds=embeds, + ) + except hikari.NotFoundError: + logger.info("Starboard message does not exist, creating new") + message = await plugin.client.rest.create_message( + settings.channel_id, + embeds=embeds, + ) + async with Session() as session: + stmt = ( + update(Starboard) + .where( + Starboard.starboard_message_id + == starboard.starboard_message_id + ) + .values( + starboard_message_id=message.id, + ) + ) + await session.execute(stmt) + await session.commit() + + except hikari.ForbiddenError: + logger.info("Can't access starboard channel") + + async with Session() as session: + stmt = ( + update(StarboardSettings) + .where(StarboardSettings.guild_id == event.guild_id) + .values(error=StarboardSettingsError.CHANNEL_FORBIDDEN) + ) + await session.execute(stmt) + await session.commit() + except hikari.NotFoundError: + logger.info("Can't find starboard channel") + + async with Session() as session: + stmt = ( + update(StarboardSettings) + .where(StarboardSettings.guild_id == event.guild_id) + .values(error=StarboardSettingsError.CHANNEL_NOT_FOUND) ) - except hikari.ForbiddenError: - logger.info("Can't edit starboard message") - stmt = delete(StarboardSettings).where(StarboardSettings.guild == event.guild_id) + await session.execute(stmt) + await session.commit() - async with session.begin() as conn: - await conn.execute(stmt) - await conn.commit() +# TODO: add permission hook @plugin.include -@arc.slash_command("starboard", "Edit or view starboard settings.", default_permissions=hikari.Permissions.MANAGE_GUILD) +@arc.slash_command( + "starboard", + "Edit or view starboard settings.", + default_permissions=hikari.Permissions.MANAGE_GUILD, +) async def starboard_settings( ctx: arc.GatewayContext, - channel: arc.Option[hikari.TextableGuildChannel | None, arc.ChannelParams("The channel to post starboard messages to.")] = None, - threshold: arc.Option[int | None, arc.IntParams("The minimum number of stars before this message is posted to the starboard", min=1)] = None, - session: AsyncEngine = arc.inject(), + channel: arc.Option[ + hikari.TextableGuildChannel | None, + arc.ChannelParams("The channel to post starboard messages to."), + ] = None, + threshold: arc.Option[ + int | None, + arc.IntParams( + "The minimum number of stars before this message is posted to the starboard", + min=1, + ), + ] = None, ) -> None: assert ctx.guild_id - stmt = select(StarboardSettings).where(StarboardSettings.guild == ctx.guild_id) - async with session.connect() as conn: - result = await conn.execute(stmt) - - settings = result.first() + async with Session() as session: + stmt = select(StarboardSettings).where( + StarboardSettings.guild_id == ctx.guild_id + ) + result = await session.execute(stmt) + settings = result.scalars().first() if not channel and not threshold: if not settings: - await ctx.respond("This server has no starboard settings.", flags=hikari.MessageFlag.EPHEMERAL) + await ctx.respond( + "This server has no starboard settings.", + flags=hikari.MessageFlag.EPHEMERAL, + ) else: # TODO: `channel` and `threshold` can be None embed = hikari.Embed( title="Starboard Settings", description=( - f"**Channel:** <#{settings.channel}>\n" - f"**Threshold:** {settings.threshold}" + f"**Channel:** <#{settings.channel_id}>\n" + f"**Threshold:** {settings.threshold}\n" + + (f"**Error:** {settings.error}" if settings.error else "") ), ) await ctx.respond(embed) - + return - + + # TODO: use returning statement to get back new row + # then send embed + if not settings: - stmt = insert(StarboardSettings).values(guild=ctx.guild_id) + # TODO: use add not insert + stmt = insert(StarboardSettings).values(guild_id=ctx.guild_id) else: - stmt = update(StarboardSettings).where(StarboardSettings.guild == ctx.guild_id) + stmt = update(StarboardSettings).where( + StarboardSettings.guild_id == ctx.guild_id + ) # TODO: simplify logic if channel and threshold: - stmt = stmt.values(channel=channel.id, threshold=threshold) + stmt = stmt.values(channel_id=channel.id, threshold=threshold) elif channel: - stmt = stmt.values(channel=channel.id) + stmt = stmt.values(channel_id=channel.id) elif threshold: stmt = stmt.values(threshold=threshold) - async with session.begin() as conn: - await conn.execute(stmt) - await conn.commit() - - # TODO: respond with embed of new settings? + async with Session() as session: + await session.execute(stmt) + await session.commit() + await ctx.respond("Settings updated.", flags=hikari.MessageFlag.EPHEMERAL) + @arc.loader def loader(client: arc.GatewayClient) -> None: client.add_plugin(plugin)