Skip to content

Conversation

@Atmois
Copy link
Contributor

@Atmois Atmois commented Aug 22, 2024

Added two hybrid moderation commands, snippet ban {prefix}snippetban and snippet unban {prefix}snippetunban to prevent users from creating snippets. Both are registered as cases and have checks to ensure a snippet banned user isn't snippet banned again and vice versa. Requires Mod (Level 3) permissions to use.
Closes #439

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Aug 22, 2024

Reviewer's Guide by Sourcery

This pull request implements snippet banning and unbanning functionality for a Discord bot. It adds two new moderation commands, snippetban and snippetunban, which allow moderators to prevent users from creating snippets. The implementation includes new flag classes for command arguments, modifications to existing files to support the new functionality, and two new files for the snippet ban and unban commands. The changes also include updates to the case management system to handle these new moderation actions.

File-Level Changes

Files Changes
tux/utils/flags.py Added new flag classes SnippetBanFlags and SnippetUnbanFlags for handling command arguments
tux/cogs/utility/snippets.py Implemented is_snippetbanned method to check if a user is currently snippet banned
tux/cogs/utility/snippets.py Added snippet ban check in the create_snippet command to prevent banned users from creating snippets
tux/cogs/moderation/cases.py Updated case management system to include new case types for snippet ban and unban
tux/cogs/moderation/snippetban.py Created new SnippetBan cog with snippet_ban command and related functionality
tux/cogs/moderation/snippetunban.py Created new SnippetUnban cog with snippet_unban command and related functionality

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Atmois - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 4 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

)


class SnippetBanFlags(commands.FlagConverter, delimiter=" ", prefix="-"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider creating a base class for flag converters to reduce duplication

The SnippetBanFlags, SnippetUnbanFlags, and WarnFlags classes share similar structure. Consider creating a base class to reduce code duplication and improve maintainability.

class BaseFlags(commands.FlagConverter, delimiter=" ", prefix="-"):
    pass

class SnippetBanFlags(BaseFlags):

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

async def is_snippetbanned(self, guild_id: int, user_id: int) -> bool:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Move is_snippetbanned method to a common location to avoid duplication

This method is duplicated in both snippetban.py and snippetunban.py. Consider moving it to a shared utility module or base class to ensure consistency and reduce duplication.

from tux.utils.moderation import is_snippetbanned

class SnippetBan(commands.Cog):
    # ... existing code ...

    @commands.command()
    async def snippetban(self, ctx, user: discord.Member):
        if await is_snippetbanned(self.case_controller, ctx.guild.id, user.id):
            # ... rest of the method

await self.send_dm(ctx, flags.silent, target, flags.reason, "Snippet Banned")
await self.handle_case_response(ctx, case, "created", flags.reason, target)

async def handle_case_response(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Refactor shared functionality into a base class

The handle_case_response method and overall command structure are very similar in both snippetban.py and snippetunban.py. Consider creating a base class or utility functions to reduce code duplication and improve maintainability.

class SnippetModBase:
    async def handle_case_response(
        self,
        ctx: commands.Context[commands.Bot],
        case: Case,
        action: str,
        reason: str,
        target: discord.Member
    ) -> None:
        # Implementation here

await ctx.send("This command cannot be used in direct messages.")
return

if await self.is_snippetbanned(ctx.guild.id, ctx.author.id):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Consider optimizing the is_snippetbanned check

The current implementation of is_snippetbanned fetches all cases and then counts them. Consider optimizing this by using a more efficient database query to directly get the count or the latest status.

        snippet_ban_status = await self.get_snippet_ban_status(ctx.guild.id, ctx.author.id)
        if snippet_ban_status:
            await ctx.send("You are banned from using snippets.")
            return

self.config = DatabaseController().guild_config
self.case_controller = CaseController()

async def is_snippetbanned(self, guild_id: int, user_id: int) -> bool:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider separating the user ban check into a utility function or service.

The new code introduces additional complexity due to the added dependencies on CaseController and CaseType, as well as the new is_snippetbanned method. This increases coupling and makes the code harder to maintain. To improve, consider separating the concern of checking if a user is banned into a utility function or service, which would keep the Snippets class focused on its primary responsibility. Additionally, if possible, simplify the logic for determining if a user is banned, perhaps by leveraging a method in CaseController that directly checks this status. This refactoring would enhance readability and maintainability.

unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETUNBAN)

ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
unban_count = sum(1 for case in unban_cases if case.case_target_id == user_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Simplify constant sum() call (simplify-constant-sum)

Suggested change
unban_count = sum(1 for case in unban_cases if case.case_target_id == user_id)
unban_count = sum(bool(case.case_target_id == user_id)


ExplanationAs sum add the values it treats True as 1, and False as 0. We make use
of this fact to simplify the generator expression inside the sum call.

ban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETBAN)
unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETUNBAN)

ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Simplify constant sum() call (simplify-constant-sum)

Suggested change
ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
ban_count = sum(bool(case.case_target_id == user_id)


ExplanationAs sum add the values it treats True as 1, and False as 0. We make use
of this fact to simplify the generator expression inside the sum call.

unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETUNBAN)

ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
unban_count = sum(1 for case in unban_cases if case.case_target_id == user_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Simplify constant sum() call (simplify-constant-sum)

Suggested change
unban_count = sum(1 for case in unban_cases if case.case_target_id == user_id)
unban_count = sum(bool(case.case_target_id == user_id)


ExplanationAs sum add the values it treats True as 1, and False as 0. We make use
of this fact to simplify the generator expression inside the sum call.

ban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETBAN)
unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETUNBAN)

ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Simplify constant sum() call (simplify-constant-sum)

Suggested change
ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
ban_count = sum(bool(case.case_target_id == user_id)


ExplanationAs sum add the values it treats True as 1, and False as 0. We make use
of this fact to simplify the generator expression inside the sum call.

unban_cases = await self.case_controller.get_all_cases_by_type(guild_id, CaseType.SNIPPETUNBAN)

ban_count = sum(1 for case in ban_cases if case.case_target_id == user_id)
unban_count = sum(1 for case in unban_cases if case.case_target_id == user_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Simplify constant sum() call (simplify-constant-sum)

Suggested change
unban_count = sum(1 for case in unban_cases if case.case_target_id == user_id)
unban_count = sum(bool(case.case_target_id == user_id)


ExplanationAs sum add the values it treats True as 1, and False as 0. We make use
of this fact to simplify the generator expression inside the sum call.

@kzndotsh kzndotsh merged commit fdd2360 into main Aug 23, 2024
@kzndotsh kzndotsh deleted the snippetban branch August 23, 2024 16:23
@sentry
Copy link

sentry bot commented Aug 24, 2024

Suspect Issues

This pull request was deployed and Sentry observed the following issues:

  • ‼️ DataError: Error occurred during query execution: tux.database.controllers.case in get_all_cases_... View Issue

Did you find this useful? React with a 👍 or 👎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Snippet banning/unbanning

3 participants