Skip to content

Commit

Permalink
feat: version 3.23 (#81)
Browse files Browse the repository at this point in the history
* chore: bump version

* feat: add guild_id to up and down votes on suggestion logs

* feat: add traceback to error log

* fix: R2 having double trailing dot

Closes BT-34

* feat: Support newline characters in suggestions

Closes BT-36

* refactor: add support for raw message deleting without two fetch calls

Closes BT-21

* refactor: move try_fetch_icon_url to within the bot

Closes BT-20

* chore: remove unused method

* chore: various IDE reported code fixes

* feat: ping authors in suggestion threads on create

Closes BT-32

* feat: bump zonis to 2.0

Closes BT-35

* fix: racing in suggestion resolve flow

Closes BT-18
  • Loading branch information
Skelmis authored Mar 29, 2024
1 parent 7d4d849 commit ae031be
Show file tree
Hide file tree
Showing 15 changed files with 117 additions and 145 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
Expand Down Expand Up @@ -128,7 +127,6 @@ celerybeat.pid
*.sage.py

# Environments
.env
.venv
env/
venv/
Expand Down
1 change: 0 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import logging
import os
import tracemalloc

import alaric
from alaric import Cursor
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ tomli==2.0.1
typing_extensions==4.3.0
websockets==10.4
yarl==1.7.2
zonis==1.2.5
zonis==2.0.0
types-aiobotocore==2.11.2
aiobotocore==2.11.2
logoo==1.3.0
22 changes: 20 additions & 2 deletions suggestions/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import traceback
from pathlib import Path
from string import Template
from typing import Type, Optional
from typing import Type, Optional, Union

import aiohttp
import alaric
Expand Down Expand Up @@ -54,7 +54,7 @@

class SuggestionsBot(commands.AutoShardedInteractionBot, BotBase):
def __init__(self, *args, **kwargs):
self.version: str = "Public Release 3.22"
self.version: str = "Public Release 3.23"
self.main_guild_id: int = 601219766258106399
self.legacy_beta_role_id: int = 995588041991274547
self.automated_beta_role_id: int = 998173237282361425
Expand Down Expand Up @@ -987,3 +987,21 @@ async def inner():
task_1 = asyncio.create_task(inner())
self.state.add_background_task(task_1)
log.info("Setup status notifications")

async def delete_message(self, *, message_id: int, channel_id: int):
await self._connection.http.delete_message(channel_id, message_id)

async def try_fetch_icon_url(self, guild_id: int) -> Union[None, str]:
"""Given an id and state, return either the guilds icon or None."""
if guild_id not in self.state.guild_cache:
guild = await self.state.bot.fetch_guild(guild_id)
self.state.refresh_guild_cache(guild)
else:
guild = self.state.guild_cache.get_entry(guild_id)

if not guild.icon:
# Update cache if we don't have it
guild = await self.state.bot.fetch_guild(guild_id)
self.state.refresh_guild_cache(guild)

return None if not guild.icon else guild.icon.url
4 changes: 3 additions & 1 deletion suggestions/clunk2/edits.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import asyncio
from typing import TYPE_CHECKING

import commons
import disnake
from logoo import Logger

Expand Down Expand Up @@ -60,13 +61,14 @@ async def update_suggestion_message(
channel_id=up_to_date_suggestion.channel_id,
message_id=up_to_date_suggestion.message_id,
).edit(embed=await up_to_date_suggestion.as_embed(bot))
except (disnake.HTTPException, disnake.NotFound):
except (disnake.HTTPException, disnake.NotFound) as e:
logger.error(
"Failed to update suggestion %s",
suggestion.suggestion_id,
extra_metadata={
"guild_id": suggestion.guild_id,
"suggestion_id": suggestion.suggestion_id,
"traceback": commons.exception_as_string(e),
},
)

Expand Down
6 changes: 3 additions & 3 deletions suggestions/cogs/guild_config_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import cooldowns
import disnake
from disnake import Guild
from disnake.ext import commands
from logoo import Logger

Expand Down Expand Up @@ -118,6 +117,7 @@ async def queue_channel(
interaction.guild_id, self.state
)
try:
# BT-21 doesn't apply here as we are sending not fetching
message = await channel.send("This is a test message and can be ignored.")
await message.delete()
except disnake.Forbidden:
Expand Down Expand Up @@ -222,7 +222,7 @@ async def get(
guild_config: GuildConfig = await GuildConfig.from_id(
interaction.guild_id, self.state
)
icon_url = await Guild.try_fetch_icon_url(interaction.guild_id, self.state)
icon_url = await self.bot.try_fetch_icon_url(interaction.guild_id)
guild = self.state.guild_cache.get_entry(interaction.guild_id)
embed: disnake.Embed = disnake.Embed(
description=self.bot.get_locale(
Expand Down Expand Up @@ -552,7 +552,7 @@ async def send_full_config(self, interaction: disnake.GuildCommandInteraction):
locale_string, interaction
)

icon_url = await Guild.try_fetch_icon_url(interaction.guild_id, self.state)
icon_url = await self.bot.try_fetch_icon_url(interaction.guild_id)
guild = self.state.guild_cache.get_entry(interaction.guild_id)
embed: disnake.Embed = disnake.Embed(
description=f"Configuration for {guild.name}\n\nSuggestions channel: {suggestions_channel}\n"
Expand Down
48 changes: 25 additions & 23 deletions suggestions/cogs/suggestion_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
import cooldowns
import disnake
from commons.caching import NonExistentEntry
from bot_base.wraps import WrappedChannel
from disnake import Guild, ButtonStyle
from disnake import ButtonStyle
from disnake.ext import commands, components
from logoo import Logger

Expand All @@ -21,8 +20,7 @@
MissingQueueLogsChannel,
)
from suggestions.interaction_handler import InteractionHandler
from suggestions.objects import Suggestion, GuildConfig, UserConfig, QueuedSuggestion

from suggestions.objects import Suggestion, GuildConfig, QueuedSuggestion
from suggestions.objects.suggestion import SuggestionState
from suggestions.utility import r2

Expand Down Expand Up @@ -84,7 +82,10 @@ async def suggestion_up_vote(
)
logger.debug(
f"Member {member_id} modified their vote on {suggestion_id} to a up vote",
extra_metadata={"suggestion_id": suggestion_id},
extra_metadata={
"suggestion_id": suggestion_id,
"guild_id": inter.guild_id,
},
)
else:
suggestion.up_voted_by.add(member_id)
Expand All @@ -98,7 +99,10 @@ async def suggestion_up_vote(
)
logger.debug(
f"Member {member_id} up voted {suggestion_id}",
extra_metadata={"suggestion_id": suggestion_id},
extra_metadata={
"suggestion_id": suggestion_id,
"guild_id": inter.guild_id,
},
)

await update_suggestion_message(suggestion=suggestion, bot=self.bot)
Expand Down Expand Up @@ -146,7 +150,10 @@ async def suggestion_down_vote(
)
logger.debug(
f"Member {member_id} modified their vote on {suggestion_id} to a down vote",
extra_metadata={"suggestion_id": suggestion_id},
extra_metadata={
"suggestion_id": suggestion_id,
"guild_id": inter.guild_id,
},
)
else:
suggestion.down_voted_by.add(member_id)
Expand All @@ -160,7 +167,10 @@ async def suggestion_down_vote(
)
logger.debug(
f"Member {member_id} down voted {suggestion_id}",
extra_metadata={"suggestion_id": suggestion_id},
extra_metadata={
"suggestion_id": suggestion_id,
"guild_id": inter.guild_id,
},
)

await update_suggestion_message(suggestion=suggestion, bot=self.bot)
Expand Down Expand Up @@ -214,6 +224,8 @@ async def suggest(

await interaction.response.defer(ephemeral=True)

suggestion: str = suggestion.replace("\\n", "\n")

guild_config: GuildConfig = await GuildConfig.from_id(
interaction.guild_id, self.state
)
Expand Down Expand Up @@ -302,7 +314,7 @@ async def suggest(
),
)

icon_url = await Guild.try_fetch_icon_url(interaction.guild_id, self.state)
icon_url = await self.bot.try_fetch_icon_url(interaction.guild_id)
guild = self.state.guild_cache.get_entry(interaction.guild_id)
suggestion: Suggestion = await Suggestion.new(
suggestion=suggestion,
Expand All @@ -314,9 +326,7 @@ async def suggest(
)
await suggestion.setup_initial_messages(
guild_config=guild_config,
interaction=interaction,
state=self.state,
bot=self.bot,
ih=await InteractionHandler.new_handler(interaction),
cog=self,
guild=guild,
icon_url=icon_url,
Expand Down Expand Up @@ -490,17 +500,9 @@ async def clear(
suggestion_id, interaction.guild_id, self.state
)
if suggestion.channel_id and suggestion.message_id:
try:
channel: WrappedChannel = await self.bot.get_or_fetch_channel(
suggestion.channel_id
)
message: disnake.Message = await channel.fetch_message(
suggestion.message_id
)
except disnake.HTTPException:
pass
else:
await message.delete()
await self.bot.delete_message(
message_id=suggestion.message_id, channel_id=suggestion.channel_id
)

await suggestion.mark_cleared_by(self.state, interaction.user.id, response)
await interaction.send(
Expand Down
12 changes: 0 additions & 12 deletions suggestions/cogs/suggestion_queue_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,6 @@ async def virtual_reject_button(
await InteractionHandler.new_handler(inter), pid
)

@components.button_listener()
async def accept_queued_suggestion(self, inter: disnake.MessageInteraction):
if inter.message is None:
raise ValueError("Unhandled exception, expected a message")

await self.core.accept_queued_suggestion(
await InteractionHandler.new_handler(inter),
inter.message.id,
inter.message.channel.id,
self.accept_queued_suggestion,
)

@commands.slash_command(
dm_permission=False,
default_member_permissions=disnake.Permissions(manage_guild=True),
Expand Down
66 changes: 7 additions & 59 deletions suggestions/core/suggestions_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from alaric.meta import Negate
from alaric.projections import Projection, SHOW
from commons.caching import NonExistentEntry, TimedCache
from disnake import Guild

from suggestions.exceptions import ErrorHandled, MissingQueueLogsChannel
from suggestions.interaction_handler import InteractionHandler
Expand Down Expand Up @@ -129,13 +128,11 @@ async def resolve_queued_suggestion(
suggestion = await queued_suggestion.convert_to_suggestion(
self.bot.state
)
icon_url = await Guild.try_fetch_icon_url(guild_id, self.state)
icon_url = await self.bot.try_fetch_icon_url(guild_id)
guild = await self.state.fetch_guild(guild_id)
await suggestion.setup_initial_messages(
guild_config=guild_config,
interaction=ih.interaction,
state=self.state,
bot=self.bot,
ih=ih,
cog=self.bot.get_cog("SuggestionsCog"),
guild=guild,
icon_url=icon_url,
Expand All @@ -162,7 +159,7 @@ async def resolve_queued_suggestion(
user_config: UserConfig = await UserConfig.from_id(
queued_suggestion.suggestion_author_id, self.bot.state
)
icon_url = await Guild.try_fetch_icon_url(guild_id, self.state)
icon_url = await self.bot.try_fetch_icon_url(guild_id)
guild = self.state.guild_cache.get_entry(guild_id)
if (
user_config.dm_messages_disabled
Expand Down Expand Up @@ -192,11 +189,10 @@ async def resolve_queued_suggestion(
await self.bot.state.suggestions_db.delete(suggestion)

if suggestion.message_id is not None:
channel: disnake.TextChannel = await self.state.fetch_channel(
suggestion.channel_id
await self.bot.delete_message(
message_id=suggestion.message_id,
channel_id=suggestion.channel_id,
)
message = await channel.fetch_message(suggestion.message_id)
await message.delete()

# Re-raise for the bot handler
raise
Expand Down Expand Up @@ -236,7 +232,7 @@ async def info(self, ih: InteractionHandler):
count: int = await self.queued_suggestions_db.count(
AQ(AND(EQ("guild_id", guild_id), EQ("still_in_queue", True)))
)
icon_url = await Guild.try_fetch_icon_url(guild_id, self.state)
icon_url = await self.bot.try_fetch_icon_url(guild_id)
guild = self.state.guild_cache.get_entry(guild_id)
embed = disnake.Embed(
title="Queue Info",
Expand Down Expand Up @@ -320,51 +316,3 @@ async def view(
],
)
self.paginator_objects.add_entry(pid, paginator)

async def accept_queued_suggestion(
self, ih: InteractionHandler, message_id: int, channel_id: int, button
):
current_suggestion: QueuedSuggestion = await QueuedSuggestion.from_message_id(
message_id, channel_id, self.state
)
if current_suggestion.is_resolved:
return await ih.send(translation_key="QUEUE_INNER_ALREADY_RESOLVED")

# By here we need to do something about resolving it
suggestion: None = None
guild_id = ih.interaction.guild_id
try:
await paginator.remove_current_page()
suggestion: Suggestion = await current_suggestion.resolve(
was_approved=True,
state=self.bot.state,
resolved_by=ih.interaction.author.id,
)
guild_config: GuildConfig = await GuildConfig.from_id(guild_id, self.state)
icon_url = await Guild.try_fetch_icon_url(guild_id, self.state)
guild = self.state.guild_cache.get_entry(guild_id)
await suggestion.setup_initial_messages(
guild_config=guild_config,
interaction=ih.interaction,
state=self.state,
bot=self.bot,
cog=self.bot.get_cog("SuggestionsCog"),
guild=guild,
icon_url=icon_url,
comes_from_queue=True,
)
except:
# Throw it back in the queue on error
current_suggestion.resolved_by = None
current_suggestion.resolved_at = None
current_suggestion.still_in_queue = True
await self.bot.state.queued_suggestions_db.update(
current_suggestion, current_suggestion
)

if suggestion is not None:
await self.bot.state.suggestions_db.delete(suggestion)

raise

await ih.send(translation_key="PAGINATION_INNER_QUEUE_ACCEPTED")
1 change: 1 addition & 0 deletions suggestions/locales/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"SUGGEST_INNER_SENT_TO_QUEUE": "Your suggestion has been sent to the queue for processing.",
"SUGGEST_INNER_NO_ANONYMOUS_SUGGESTIONS": "Your guild does not allow anonymous suggestions.",
"SUGGEST_INNER_NO_IMAGES_IN_SUGGESTIONS": "Your guild does not allow images in suggestions.",
"SUGGEST_INNER_PING_AUTHOR_IN_THREAD": "Hey <@$AUTHOR_ID>, I have created this thread for you to discuss your suggestion in.",
"CONFIG_ANONYMOUS_ENABLE_INNER_SUCCESS": "I have enabled anonymous suggestions for this guild.",
"CONFIG_ANONYMOUS_DISABLE_INNER_SUCCESS": "I have disabled anonymous suggestions for this guild.",
"SUGGESTION_OBJECT_LOCK_THREAD": "Locking this thread as the suggestion has reached a resolution.",
Expand Down
2 changes: 1 addition & 1 deletion suggestions/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ async def shutdown(

await bot.graceful_shutdown()

async def graceful_shutdown(bot: SuggestionsBot, signame):
async def graceful_shutdown(bot: SuggestionsBot, _):
await bot.graceful_shutdown()

# https://github.com/gearbot/GearBot/blob/live/GearBot/GearBot.py
Expand Down
Loading

0 comments on commit ae031be

Please sign in to comment.