Skip to content

Commit

Permalink
feat: add block listing for suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
Skelmis committed Aug 12, 2023
1 parent e90cb33 commit a70ac00
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 2 deletions.
12 changes: 12 additions & 0 deletions suggestions/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
ConfiguredChannelNoLongerExists,
UnhandledError,
QueueImbalance,
BlocklistedUser,
)
from suggestions.http_error_parser import try_parse_http_error
from suggestions.objects import Error, GuildConfig, UserConfig
Expand Down Expand Up @@ -414,6 +415,17 @@ async def on_slash_command_error(
ephemeral=True,
)

elif isinstance(exception, BlocklistedUser):
return await interaction.send(
embed=self.error_embed(
"Blocked Action",
"Administrators from this guild have removed your ability to run this action.",
error_code=ErrorCode.BLOCKLISTED_USER,
error=error,
),
ephemeral=True,
)

elif isinstance(exception, ConfiguredChannelNoLongerExists):
return await interaction.send(
embed=self.error_embed(
Expand Down
17 changes: 16 additions & 1 deletion suggestions/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from disnake.ext import commands

from suggestions.exceptions import (
BetaOnly,
MissingSuggestionsChannel,
MissingLogsChannel,
BlocklistedUser,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -62,3 +62,18 @@ async def check(interaction: disnake.Interaction):
return True

return commands.check(check) # type: ignore


def ensure_user_is_not_blocklisted():
async def check(interaction: disnake.Interaction):
guild_config: Optional[GuildConfig] = await fetch_guild_config(interaction)

if not bool(guild_config):
return True

if interaction.author.id in guild_config.blocked_users:
raise BlocklistedUser

return True

return commands.check(check) # type: ignore
2 changes: 2 additions & 0 deletions suggestions/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class ErrorCode(IntEnum):
MISSING_SEND_PERMISSIONS_IN_SUGGESTION_CHANNEL = 18
MISSING_THREAD_CREATE_PERMISSIONS = 19
QUEUE_IMBALANCE = 20
MISSING_QUEUE_CHANNEL = 21
BLOCKLISTED_USER = 22

@classmethod
def from_value(cls, value: int) -> ErrorCode:
Expand Down
140 changes: 140 additions & 0 deletions suggestions/cogs/blacklist_cog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING

import disnake
from bot_base import NonExistentEntry
from disnake.ext import commands

from suggestions.objects import GuildConfig, Suggestion

if TYPE_CHECKING:
from suggestions import State, SuggestionsBot

log = logging.getLogger(__name__)


class BlacklistCog(commands.Cog):
def __init__(self, bot):
self.bot: SuggestionsBot = bot
self.state: State = self.bot.state

@commands.slash_command()
async def user(self, interaction: disnake.GuildCommandInteraction):
...

@user.sub_command_group()
async def blocklist(self, interaction: disnake.GuildCommandInteraction):
...

@blocklist.sub_command()
async def add(
self,
interaction: disnake.GuildCommandInteraction,
suggestion_id: str = commands.Param(),
):
"""
{{USER_BLOCKLIST_ADD}}
Parameters
----------
suggestion_id: str {{SUGGESTION_ID}}
"""
await interaction.response.defer(ephemeral=True)
suggestion: Suggestion = await Suggestion.from_id(
suggestion_id, interaction.guild_id, self.state
)
guild_config: GuildConfig = await GuildConfig.from_id(
interaction.guild_id, self.state
)
if suggestion.suggestion_author_id in guild_config.blocked_users:
return await interaction.send(
"This user is already blocked from creating new suggestions.",
ephemeral=True,
)

guild_config.blocked_users.add(suggestion.suggestion_author_id)
await self.bot.db.guild_configs.upsert(guild_config, guild_config)
await interaction.send(
"I have added that user to the blocklist. "
"They will be unable to create suggestions in the future.",
ephemeral=True,
)

@blocklist.sub_command()
async def remove(
self,
interaction: disnake.GuildCommandInteraction,
suggestion_id: str = commands.Param(default=None),
user_id: str = commands.Param(default=None),
):
"""
{{USER_BLOCKLIST_REMOVE}}
Parameters
----------
suggestion_id: str {{SUGGESTION_ID}}
user_id: str {{USER_ID}}
"""
await interaction.response.defer(ephemeral=True)
if suggestion_id and user_id:
return await interaction.send(
"Providing suggestion_id and user_id at the same time is not supported.",
ephemeral=True,
)

if suggestion_id:
suggestion: Suggestion = await Suggestion.from_id(
suggestion_id, interaction.guild_id, self.state
)
user_id = suggestion.suggestion_author_id

if user_id:
try:
user_id = int(user_id)
except ValueError:
return await interaction.send("User id is not valid.", ephemeral=True)

guild_config: GuildConfig = await GuildConfig.from_id(
interaction.guild_id, self.state
)
guild_config.blocked_users.discard(user_id)
await self.bot.db.guild_configs.upsert(guild_config, guild_config)
await interaction.send("I have un-blocklisted that user for you.")

@add.autocomplete("suggestion_id")
@remove.autocomplete("suggestion_id")
async def get_sid_for(
self,
interaction: disnake.ApplicationCommandInteraction,
user_input: str,
):
try:
values: list[str] = self.state.autocomplete_cache.get_entry(
interaction.guild_id
)
except NonExistentEntry:
values: list[str] = await self.state.populate_sid_cache(
interaction.guild_id
)
else:
if not values:
log.debug(
"Values was found, but empty in guild %s thus populating",
interaction.guild_id,
)
values: list[str] = await self.state.populate_sid_cache(
interaction.guild_id
)

possible_choices = [v for v in values if user_input.lower() in v.lower()]

if len(possible_choices) > 25:
return []

return possible_choices


def setup(bot):
bot.add_cog(BlacklistCog(bot))
1 change: 1 addition & 0 deletions suggestions/cogs/suggestion_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ async def suggestion_down_vote(
dm_permission=False,
)
@cooldowns.cooldown(1, 3, bucket=InteractionBucket.author)
@checks.ensure_user_is_not_blocklisted()
@checks.ensure_guild_has_suggestions_channel()
async def suggest(
self,
Expand Down
4 changes: 4 additions & 0 deletions suggestions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ class UnhandledError(Exception):

class QueueImbalance(disnake.DiscordException):
"""This queued suggestion has already been dealt with in another queue."""


class BlocklistedUser(CheckFailure):
"""This user is blocked from taking this action in this guild."""
10 changes: 9 additions & 1 deletion suggestions/locales/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,13 @@
"CONFIG_GET_INNER_IMAGES_IN_SUGGESTIONS_MESSAGE": "This guild {} have images in suggestions.",
"CONFIG_SUGGESTIONS_IMAGES_ENABLE_INNER_MESSAGE": "All new suggestions can include images.",
"CONFIG_SUGGESTIONS_IMAGES_DISABLE_INNER_MESSAGE": "All new suggestions cannot include images.",
"VIEW_VOTERS_INNER_EMBED_TITLE": "Viewing voters"
"VIEW_VOTERS_INNER_EMBED_TITLE": "Viewing voters",
"USER_BLOCKLIST_ADD_NAME": "add",
"USER_BLOCKLIST_ADD_DESCRIPTION": "Remove a users ability to create suggestions.",
"USER_BLOCKLIST_REMOVE_NAME": "remove",
"USER_BLOCKLIST_REMOVE_DESCRIPTION": "Re-add a users ability to create suggestions.",
"SUGGESTION_ID_NAME": "suggestion_id",
"SUGGESTION_ID_DESCRIPTION": "The suggestions ID you wish to reference.",
"USER_ID_NAME": "user_id",
"USER_ID_DESCRIPTION": "The users discord id."
}
6 changes: 6 additions & 0 deletions suggestions/objects/guild_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(
uses_suggestion_queue: bool = False,
can_have_images_in_suggestions: bool = True,
anonymous_resolutions: bool = False,
blocked_users: Optional[list[int]] = None,
**kwargs,
):
self._id: int = _id
Expand All @@ -41,6 +42,10 @@ def __init__(
self.can_have_anonymous_suggestions: bool = can_have_anonymous_suggestions
self.can_have_images_in_suggestions: bool = can_have_images_in_suggestions

if blocked_users is None:
blocked_users = set()
self.blocked_users: set[int] = set(blocked_users)

@property
def guild_id(self) -> int:
return self._id
Expand Down Expand Up @@ -82,6 +87,7 @@ def as_dict(self) -> Dict:
return {
"_id": self.guild_id,
"keep_logs": self.keep_logs,
"blocked_users": list(self.blocked_users),
"log_channel_id": self.log_channel_id,
"auto_archive_threads": self.auto_archive_threads,
"dm_messages_disabled": self.dm_messages_disabled,
Expand Down

0 comments on commit a70ac00

Please sign in to comment.