Skip to content
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
2 changes: 2 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,6 @@ enum CaseType {
UNJAIL
SNIPPETUNBAN
UNTEMPBAN
POLLBAN
POLLUNBAN
}
28 changes: 28 additions & 0 deletions tux/cogs/moderation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,31 @@ async def handle_case_response(

await self.send_embed(ctx, embed, log_type="mod")
await ctx.send(embed=embed, delete_after=30, ephemeral=True)

async def is_pollbanned(self, guild_id: int, user_id: int) -> bool:
"""
Check if a user is poll banned.

Parameters
----------
guild_id : int
The ID of the guild to check in.
user_id : int
The ID of the user to check.

Returns
-------
bool
True if the user is poll banned, False otherwise.
"""

# ban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.POLLBAN)
# unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.POLLUNBAN)

ban_cases = await self.db.case.get_all_cases_by_type(guild_id, CaseType.POLLBAN)
unban_cases = await self.db.case.get_all_cases_by_type(guild_id, CaseType.POLLUNBAN)

ban_count = sum(case.case_user_id == user_id for case in ban_cases)
unban_count = sum(case.case_user_id == user_id for case in unban_cases)

return ban_count > unban_count
71 changes: 71 additions & 0 deletions tux/cogs/moderation/pollban.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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.case import CaseController
from tux.utils import checks
from tux.utils.flags import PollBanFlags, generate_usage

from . import ModerationCogBase


class PollBan(ModerationCogBase):
def __init__(self, bot: Tux) -> None:
super().__init__(bot)
self.case_controller = CaseController()
self.poll_ban.usage = generate_usage(self.poll_ban, PollBanFlags)

@commands.hybrid_command(
name="pollban",
aliases=["pb"],
)
@commands.guild_only()
@checks.has_pl(3)
async def poll_ban(
self,
ctx: commands.Context[Tux],
member: discord.Member,
*,
flags: PollBanFlags,
) -> None:
"""
Ban a user from creating polls using tux.

Parameters
----------
ctx : commands.Context[Tux]
The context object.
member : discord.Member
The member to poll ban.
flags : PollBanFlags
The flags for the command. (reason: str, silent: bool)
"""

assert ctx.guild

if await self.is_pollbanned(ctx.guild.id, member.id):
await ctx.send("User is already poll banned.", delete_after=30, ephemeral=True)
return

try:
case = await self.db.case.insert_case(
case_user_id=member.id,
case_moderator_id=ctx.author.id,
case_type=CaseType.POLLBAN,
case_reason=flags.reason,
guild_id=ctx.guild.id,
)

except Exception as e:
logger.error(f"Failed to ban {member}. {e}")
await ctx.send(f"Failed to ban {member}. {e}", delete_after=30)
return

dm_sent = await self.send_dm(ctx, flags.silent, member, flags.reason, "poll banned")
await self.handle_case_response(ctx, CaseType.POLLBAN, case.case_number, flags.reason, member, dm_sent)


async def setup(bot: Tux) -> None:
await bot.add_cog(PollBan(bot))
71 changes: 71 additions & 0 deletions tux/cogs/moderation/pollunban.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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.case import CaseController
from tux.utils import checks
from tux.utils.flags import PollUnbanFlags, generate_usage

from . import ModerationCogBase


class PollUnban(ModerationCogBase):
def __init__(self, bot: Tux) -> None:
super().__init__(bot)
self.case_controller = CaseController()
self.poll_unban.usage = generate_usage(self.poll_unban, PollUnbanFlags)

@commands.hybrid_command(
name="pollunban",
aliases=["pub"],
)
@commands.guild_only()
@checks.has_pl(3)
async def poll_unban(
self,
ctx: commands.Context[Tux],
member: discord.Member,
*,
flags: PollUnbanFlags,
):
"""
Unban a user from creating snippets.

Parameters
----------
ctx : commands.Context[Tux]
The context object.
member : discord.Member
The member to snippet unban.
flags : PollUnbanFlags
The flags for the command. (reason: str, silent: bool)
"""

assert ctx.guild

if not await self.is_pollbanned(ctx.guild.id, member.id):
await ctx.send("User is not poll banned.", delete_after=30, ephemeral=True)
return

try:
case = await self.db.case.insert_case(
case_user_id=member.id,
case_moderator_id=ctx.author.id,
case_type=CaseType.POLLUNBAN,
case_reason=flags.reason,
guild_id=ctx.guild.id,
)

except Exception as e:
logger.error(f"Failed to poll unban {member}. {e}")
await ctx.send(f"Failed to poll unban {member}. {e}", delete_after=30, ephemeral=True)
return

dm_sent = await self.send_dm(ctx, flags.silent, member, flags.reason, "poll unbanned")
await self.handle_case_response(ctx, CaseType.POLLUNBAN, case.case_number, flags.reason, member, dm_sent)


async def setup(bot: Tux) -> None:
await bot.add_cog(PollUnban(bot))
48 changes: 47 additions & 1 deletion tux/cogs/utility/poll.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from discord.ext import commands
from loguru import logger

from prisma.enums import CaseType
from tux.bot import Tux
from tux.database.controllers import CaseController
from tux.ui.embeds import EmbedCreator

# TODO: Create option inputs for the poll command instead of using a comma separated string
Expand All @@ -12,6 +14,35 @@
class Poll(commands.Cog):
def __init__(self, bot: Tux) -> None:
self.bot = bot
self.case_controller = CaseController()

# TODO: for the moment this is duplicated code from ModerationCogBase in a attempt to get the code out sooner
async def is_pollbanned(self, guild_id: int, user_id: int) -> bool:
"""
Check if a user is poll banned.

Parameters
----------
guild_id : int
The ID of the guild to check in.
user_id : int
The ID of the user to check.

Returns
-------
bool
True if the user is poll banned, False otherwise.
"""

ban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.POLLBAN)
unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.POLLUNBAN)

ban_count = sum(case.case_user_id == user_id for case in ban_cases)
unban_count = sum(case.case_user_id == user_id for case in unban_cases)

return (
ban_count > unban_count
) # TODO: this implementation is flawed, if someone bans and unbans the same user multiple times, this will not work as expected

@commands.Cog.listener() # listen for messages
async def on_message(self, message: discord.Message) -> None:
Expand Down Expand Up @@ -40,7 +71,6 @@ async def on_message(self, message: discord.Message) -> None:
@commands.Cog.listener()
async def on_reaction_add(self, reaction: discord.Reaction, user: discord.User) -> None:
# Block any reactions that are not numbers for the poll

if reaction.message.embeds:
embed = reaction.message.embeds[0]
if (
Expand All @@ -64,14 +94,30 @@ async def poll(self, interaction: discord.Interaction, title: str, options: str)
The title of the poll.
options : str
The options for the poll, separated by commas.


"""
if interaction.guild_id is None:
await interaction.response.send_message("This command can only be used in a server.", ephemeral=True)
return

# Split the options by comma
options_list = options.split(",")

# Remove any leading or trailing whitespaces from the options
options_list = [option.strip() for option in options_list]

if await self.is_pollbanned(interaction.guild_id, interaction.user.id):
embed = EmbedCreator.create_embed(
bot=self.bot,
embed_type=EmbedCreator.ERROR,
user_name=interaction.user.name,
user_display_avatar=interaction.user.display_avatar.url,
title="Poll Banned",
description="You are poll banned and cannot create a poll.",
)
await interaction.response.send_message(embed=embed, ephemeral=True)
return
# Check if the options count is between 2-9
if len(options_list) < 2 or len(options_list) > 9:
embed = EmbedCreator.create_embed(
Expand Down
30 changes: 30 additions & 0 deletions tux/utils/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,33 @@ class SnippetUnbanFlags(commands.FlagConverter, case_insensitive=True, delimiter
aliases=["s", "quiet"],
default=False,
)


class PollBanFlags(commands.FlagConverter, case_insensitive=True, delimiter=" ", prefix="-"):
reason: str = commands.flag(
name="reason",
description="Reason for the poll ban.",
aliases=["r"],
default=MISSING,
)
silent: bool = commands.flag(
name="silent",
description="Do not send a DM to the target.",
aliases=["s", "quiet"],
default=False,
)


class PollUnbanFlags(commands.FlagConverter, case_insensitive=True, delimiter=" ", prefix="-"):
reason: str = commands.flag(
name="reason",
description="Reason for the poll unban",
aliases=["r"],
default=MISSING,
)
silent: bool = commands.flag(
name="silent",
description="Do not send a DM to the target.",
aliases=["s", "quiet"],
default=False,
)