Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: version 3.28 #95

Merged
merged 10 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
FROM python:3.10

# Set pip to have cleaner logs and no saved cache
ENV PIP_NO_CACHE_DIR=false

RUN mkdir -p /bot
WORKDIR bot
FROM python:3.11-alpine

WORKDIR /code
RUN pip install poetry

COPY ./pyproject.toml /bot/pyproject.toml
COPY ./poetry.lock /bot/poetry.lock

RUN poetry install

COPY . /bot
COPY . /code


CMD poetry run python3 main.py
CMD ["poetry", "run", "python", "main.py"]
1,339 changes: 849 additions & 490 deletions poetry.lock

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
[tool.poetry]
name = "suggestions bot"
version = "3.27"
version = "3.28"
description = "A Discord bot designed to build better communities by encouraging a positive and constructive relationship between community and staff."
authors = ["Your Name <[email protected]>"]
authors = ["Suggestions Bot"]
license = "AGPL-3.0"
readme = "README.md"
readme = "readme.md"
package-mode = false

[tool.poetry.dependencies]
python = "^3.10"
disnake = "2.9.2"
disnake = {extras = ["speed"], version = "2.10.1"}
alaric = "^1.5.0"
function-cooldowns = "^2.0.1"
httpx = "^0.27.2"
httpx = "^0.28.1"
orjson = "^3.10.11"
skelmis-commons = "^1.4.0"
zonis = "^2.1.0"
aiobotocore = "^2.15.2"
logoo = "^1.5.1"
disnake-ext-components = {git = "https://github.com/suggestionsbot/disnake-ext-components.git", rev = "91689ed74ffee73f631453a39e548af9b824826d"}
typing-extensions = "^4.12.2"
python-dotenv = "^1.0.1"
humanize = "^4.11.0"
disnake-ext-components = {git = "https://github.com/DisnakeCommunity/disnake-ext-components.git", rev = "rewrite"}


[tool.poetry.group.dev.dependencies]
Expand Down
11 changes: 10 additions & 1 deletion suggestions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,13 @@
from .bot import SuggestionsBot
from .main import create_bot

__all__ = ("SuggestionsBot", "State", "Colors", "Emojis", "ErrorCode", "Stats")
__all__ = (
"SuggestionsBot",
"State",
"Colors",
"Emojis",
"ErrorCode",
"Stats",
"Garven",
"buttons",
)
11 changes: 8 additions & 3 deletions suggestions/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from cooldowns import CallableOnCooldown
from disnake import Locale, LocalizationKeyError, Thread
from disnake.abc import PrivateChannel, GuildChannel
from disnake.ext import commands
from disnake.ext import commands, components
from disnake.state import AutoShardedConnectionState
from logoo import Logger

Expand Down Expand Up @@ -58,7 +58,7 @@

class SuggestionsBot(commands.AutoShardedInteractionBot):
def __init__(self, *args, **kwargs):
self.version: str = "Public Release 3.27"
self.version: str = "Public Release 3.28"
self.main_guild_id: int = 601219766258106399
self.legacy_beta_role_id: int = 995588041991274547
self.automated_beta_role_id: int = 998173237282361425
Expand Down Expand Up @@ -119,6 +119,11 @@ def __init__(self, *args, **kwargs):
# gateway_params=GatewayParams(zlib=False),
)

from suggestions import buttons

self.component_manager = components.get_manager()
self.component_manager.add_to_bot(self) # type: ignore

self._has_dispatched_initial_ready: bool = False
self._initial_ready_future: asyncio.Future = asyncio.Future()

Expand Down Expand Up @@ -777,7 +782,7 @@ async def on_slash_command_error(
"author_id": interaction.author.id,
},
)
return
raise exception

ih: InteractionHandler = await InteractionHandler.fetch_handler(
interaction.id, self
Expand Down
27 changes: 27 additions & 0 deletions suggestions/buttons/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from .suggestions_components import (
SuggestionUpVote,
SuggestionDownVote,
SuggestionsQueueApprove,
SuggestionsQueueReject,
)
from .virtual_queue import (
QueueButton,
QueueNextButton,
QueuePreviousButton,
QueueStopButton,
VirtualApproveButton,
VirtualRejectButton,
)

__all__ = (
"SuggestionUpVote",
"SuggestionDownVote",
"SuggestionsQueueApprove",
"SuggestionsQueueReject",
"QueueButton",
"QueueNextButton",
"QueuePreviousButton",
"VirtualApproveButton",
"VirtualRejectButton",
"QueueStopButton",
)
153 changes: 153 additions & 0 deletions suggestions/buttons/suggestions_components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
from __future__ import annotations

import typing

import logoo
from disnake.ext import components
from disnake.ext.components import interaction

from suggestions.clunk2 import update_suggestion_message
from suggestions.interaction_handler import InteractionHandler
from suggestions.objects import Suggestion, QueuedSuggestion
from suggestions.objects.suggestion import SuggestionState
from suggestions.utility import wrap_with_error_handler

if typing.TYPE_CHECKING:
from suggestions.cogs.suggestion_cog import SuggestionsCog

logger = logoo.Logger(__name__)
manager = components.get_manager("suggestions")


@manager.register # type: ignore
class SuggestionUpVote(components.RichButton):
suggestion_id: str

@wrap_with_error_handler()
async def callback( # type: ignore
self,
inter: components.MessageInteraction,
) -> None:
ih: InteractionHandler = await InteractionHandler.new_handler(inter._wrapped)
suggestion: Suggestion = await Suggestion.from_id(
self.suggestion_id, inter.guild_id, ih.bot.state
)
if suggestion.state != SuggestionState.pending:
return await ih.send(
translation_key="SUGGESTION_UP_VOTE_INNER_NO_MORE_CASTING"
)

member_id = inter.author.id
if member_id in suggestion.up_voted_by:
return await ih.send(
translation_key="SUGGESTION_UP_VOTE_INNER_ALREADY_VOTED"
)

if member_id in suggestion.down_voted_by:
suggestion.down_voted_by.discard(member_id)
suggestion.up_voted_by.add(member_id)
await ih.bot.state.suggestions_db.upsert(suggestion, suggestion)
# await suggestion.update_vote_count(self.bot, inter)
# lock.enqueue(suggestion.update_vote_count(self.bot, inter))
await ih.send(translation_key="SUGGESTION_UP_VOTE_INNER_MODIFIED_VOTE")
logger.debug(
f"Member {member_id} modified their vote on {self.suggestion_id} to a up vote",
extra_metadata={
"suggestion_id": self.suggestion_id,
"guild_id": inter.guild_id,
},
)
else:
suggestion.up_voted_by.add(member_id)
await ih.bot.state.suggestions_db.upsert(suggestion, suggestion)
await ih.send(translation_key="SUGGESTION_UP_VOTE_INNER_REGISTERED_VOTE")
logger.debug(
f"Member {member_id} up voted {self.suggestion_id}",
extra_metadata={
"suggestion_id": self.suggestion_id,
"guild_id": inter.guild_id,
},
)

await update_suggestion_message(suggestion=suggestion, bot=ih.bot)


@manager.register # type: ignore
class SuggestionDownVote(components.RichButton):
suggestion_id: str

@wrap_with_error_handler()
async def callback( # type: ignore
self,
inter: interaction.MessageInteraction,
) -> None:
ih: InteractionHandler = await InteractionHandler.new_handler(inter._wrapped)
suggestion: Suggestion = await Suggestion.from_id(
self.suggestion_id, inter.guild_id, ih.bot.state
)
if suggestion.state != SuggestionState.pending:
return await ih.send(
translation_key="SUGGESTION_DOWN_VOTE_INNER_NO_MORE_CASTING"
)

member_id = inter.author.id
if member_id in suggestion.down_voted_by:
return await ih.send(
translation_key="SUGGESTION_DOWN_VOTE_INNER_ALREADY_VOTED"
)

if member_id in suggestion.up_voted_by:
suggestion.up_voted_by.discard(member_id)
suggestion.down_voted_by.add(member_id)
await ih.bot.state.suggestions_db.upsert(suggestion, suggestion)
await ih.send(translation_key="SUGGESTION_DOWN_VOTE_INNER_MODIFIED_VOTE")
logger.debug(
f"Member {member_id} modified their vote on {self.suggestion_id} to a down vote",
extra_metadata={
"suggestion_id": self.suggestion_id,
"guild_id": inter.guild_id,
},
)
else:
suggestion.down_voted_by.add(member_id)
await ih.bot.state.suggestions_db.upsert(suggestion, suggestion)
await ih.send(translation_key="SUGGESTION_DOWN_VOTE_INNER_REGISTERED_VOTE")
logger.debug(
f"Member {member_id} down voted {self.suggestion_id}",
extra_metadata={
"suggestion_id": self.suggestion_id,
"guild_id": inter.guild_id,
},
)

await update_suggestion_message(suggestion=suggestion, bot=ih.bot)


@manager.register # type:ignore
class SuggestionsQueueApprove(components.RichButton):
@wrap_with_error_handler()
async def callback(self, inter: interaction.MessageInteraction):
ih = await InteractionHandler.new_handler(inter._wrapped)
qs = await QueuedSuggestion.from_message_id(
inter.message.id, inter.message.channel.id, ih.bot.state
)
cog: SuggestionsCog = ih.bot.cogs.get("SuggestionsCog") # type: ignore
await cog.qs_core.resolve_queued_suggestion(
ih, queued_suggestion=qs, was_approved=True
)
await ih.send(translation_key="PAGINATION_INNER_QUEUE_ACCEPTED")


@manager.register # type:ignore
class SuggestionsQueueReject(components.RichButton):
@wrap_with_error_handler()
async def callback(self, inter: interaction.MessageInteraction):
ih = await InteractionHandler.new_handler(inter._wrapped)
qs = await QueuedSuggestion.from_message_id(
inter.message.id, inter.message.channel.id, ih.bot.state
)
cog: SuggestionsCog = ih.bot.cogs.get("SuggestionsCog") # type: ignore
await cog.qs_core.resolve_queued_suggestion(
ih, queued_suggestion=qs, was_approved=False
)
await ih.send(translation_key="PAGINATION_INNER_QUEUE_REJECTED")
63 changes: 63 additions & 0 deletions suggestions/buttons/virtual_queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from __future__ import annotations

import typing

import logoo
from disnake.ext import components
from disnake.ext.components import interaction

from suggestions.interaction_handler import InteractionHandler
from suggestions.utility import wrap_with_error_handler

if typing.TYPE_CHECKING:
from suggestions.cogs.suggestion_queue_cog import SuggestionsQueueCog

logger = logoo.Logger(__name__)
manager = components.get_manager("suggestions")


class QueueButton(components.RichButton):
pid: str

@wrap_with_error_handler()
async def callback( # type: ignore
self,
inter: interaction.MessageInteraction,
):
ih = await InteractionHandler.new_handler(inter._wrapped)
cog: SuggestionsQueueCog = ih.bot.cogs.get("SuggestionsQueueCog") # type: ignore
await getattr(cog.core, core_mapping[self.__class__])(ih, self.pid) # type: ignore


@manager.register # type: ignore
class VirtualApproveButton(QueueButton):
pass


@manager.register # type: ignore
class VirtualRejectButton(QueueButton):
pass


@manager.register # type: ignore
class QueueStopButton(QueueButton):
pass


@manager.register # type: ignore
class QueueNextButton(QueueButton):
pass


@manager.register # type: ignore
class QueuePreviousButton(QueueButton):
pass


core_mapping = {
VirtualApproveButton: "virtual_approve_button",
VirtualRejectButton: "virtual_reject_button",
QueueStopButton: "stop_button",
QueueNextButton: "next_button",
QueuePreviousButton: "previous_button",
}
2 changes: 1 addition & 1 deletion suggestions/clunk2/edits.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from logoo import Logger

from suggestions.low_level import MessageEditing
from suggestions.objects import Suggestion

if TYPE_CHECKING:
from suggestions.objects import Suggestion
from suggestions import SuggestionsBot

logger = Logger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion suggestions/cogs/blacklist_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ def __init__(self, bot):
self.state: State = self.bot.state

@commands.slash_command(
dm_permission=False,
default_member_permissions=disnake.Permissions(manage_guild=True),
)
@commands.contexts(guild=True)
async def user(self, interaction: disnake.GuildCommandInteraction): ...

@user.sub_command_group()
Expand Down
2 changes: 1 addition & 1 deletion suggestions/cogs/guild_config_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ def __init__(self, bot):
self.stats: Stats = self.bot.stats

@commands.slash_command(
dm_permission=False,
default_member_permissions=disnake.Permissions(manage_guild=True),
)
@commands.contexts(guild=True)
@cooldowns.cooldown(1, 3, bucket=InteractionBucket.author)
async def config(self, interaction: disnake.GuildCommandInteraction):
"""Configure the bot for your guild."""
Expand Down
Loading
Loading