Skip to content

Add user nick name moderation, and change user nickname to random name - #166

Merged
PenguinBoi12 merged 7 commits into
Code-Society-Lab:mainfrom
Eyad-Jawad:user-nickname-moderation
Aug 1, 2026
Merged

Add user nick name moderation, and change user nickname to random name#166
PenguinBoi12 merged 7 commits into
Code-Society-Lab:mainfrom
Eyad-Jawad:user-nickname-moderation

Conversation

@Eyad-Jawad

@Eyad-Jawad Eyad-Jawad commented Jul 31, 2026

Copy link
Copy Markdown
Contributor
  • Add user nickname moderation feature : User nickname moderation #111, where if a user with an inappropriate name joins, their nickname will be changed to a random two words name.
  • Add a feature where users can change their name to a random two words name.
  • Add their respectful tests.

@Eyad-Jawad Eyad-Jawad changed the title Add user nick name moderation, and change user nick name to random name Add user nick name moderation, and change user nickname to random name Jul 31, 2026
@PenguinBoi12
PenguinBoi12 self-requested a review July 31, 2026 18:40
@PenguinBoi12 PenguinBoi12 added the feature New feature or request label Jul 31, 2026

@PenguinBoi12 PenguinBoi12 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's a pretty good first pass for this feature, most of the big pieces make sense and the general logic is good.

My main concern is about how you implemented validation of name, there's a simpler way to do this which I described in my comments but don't hesitate to ping me on discord about it if you need.

A few others things to look into are names of tests, they are often broad and not really descriptive of what they test.

Good job, it shouldn't take too much work to this ready to approve!

Comment thread bot/services/random_name_service.py Outdated
"""

# source : https://github.com/moby/moby/blob/master/internal/namesgenerator/names-generator.go
left = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: Why make 2 lists and not just one that you choose randomly 2 values?

Comment thread bot/services/random_name_service.py Outdated
"""

# source : https://github.com/moby/moby/blob/master/internal/namesgenerator/names-generator.go
left = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: I'd prefer having the list of names as private constant outside the function:

_NAMES = [
    ...
]


def make_random_name() -> str:
    ...

This keeps the function all about the logic that generates the code and not the data.



@patch("random.choice")
def test_random_name_service__expect_normal_output(mock_random):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

normal_output doesn't really explain what is expected. Instead, describe what is the expected output.

Comment thread bot/extensions/name_cog.py Outdated
f"Your name has an inappropriate word in it, thus it was changed from {NAME} to {good_name}."
)

@hybrid_command(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we really need a command?

Comment thread bot/extensions/name_moderation_cog.py Outdated
f"Your name has an inappropriate word in it, thus it was changed from {NAME} to {good_name}."
)

@hybrid_command(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we really need a command to generate name? I don't really see the use case for it. If it's not needed, we should probably remove it to avoid bloating the code for no reason.

Comment thread bot/extensions/name_moderation_cog.py Outdated
"""
slices_set = set(slices)

return not slices_set.isdisjoint(self.BAD_WORDS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instead of using a reverse logic and a set, you could do:

return any(s in self.BAD_WORDS for s in slices)

This is easier to read and understand what its doing.

Comment thread bot/extensions/name_moderation_cog.py Outdated
from bot.helpers.log_helper import notice


def slice_name(name: str) -> list[str]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We don't need to slice the name into every possible substring, because Python already has a built-in way to check "is this smaller string somewhere inside this bigger string?", the in operator:

"cat" in "concatenate"   # True, "cat" is inside "concatenate"
"dog" in "concatenate"   # False, "dog" is not inside "concatenate"

Instead, we can skip the cutting-up step entirely and just ask directly, for each bad word, "is this bad word inside the name?":

def contains_bad_word(self, name: str) -> bool:
    lowered = name.lower()
    return any(bad_word in lowered for bad_word in self.BAD_WORDS)

This loops over BAD_WORDS (which is a short list) instead of looping over every substring of the name (which can be a lot of substrings for a long name, a 20-character name has over 200 possible slices!). Same result, way less work, and the code reads as exactly what it's checking: "does this name contain a bad word?"

@patch("bot.extensions.name_moderation_cog.notice")
@patch("bot.extensions.name_moderation_cog.make_random_name")
@patch("bot.extensions.name_moderation_cog.slice_name")
async def test_name_moderation_on_member_join__with_normal_name__expect_nothing(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: with_none_blacklisted_name

@patch("bot.extensions.name_moderation_cog.notice")
@patch("bot.extensions.name_moderation_cog.make_random_name")
@patch("bot.extensions.name_moderation_cog.slice_name")
async def test_name_moderation_on_member_join__with_bad_name__expect_change_and_message(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: with_blacklisted_name

[["Stuff", "Name"], {"Stuff", "Name"}, True],
],
)
def test_check_slices__expecgtg_matching_output(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think there's a small typo here. Also, the name isn't descriptive enough.

@Eyad-Jawad
Eyad-Jawad requested a review from PenguinBoi12 August 1, 2026 15:33
Comment thread bot/extensions/name_moderation_cog.py Outdated

def __init__(self, bot: Grace):
self.bot: Grace = bot
self.BAD_WORDS = set(app.config.get("name_moderation", "blacklist", ""))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Uppercase name are reserved for constant, use lowercased snakecase for attributes and variable names.

https://peps.python.org/pep-0008/#naming-conventions

Comment thread bot/extensions/name_moderation_cog.py Outdated

def __init__(self, bot: Grace):
self.bot: Grace = bot
self.BAD_WORDS = set(app.config.get("name_moderation", "blacklist", ""))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The default should be a list, not an empty string

Comment thread bot/extensions/name_moderation_cog.py Outdated
class NameModerationCog(
Cog, name="Names", description="Checks and changes user's nickname."
):
"""A cog that checks when a member joins if they have a bad word in their name, and changes their name in case they do."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: it would be great if you could describe how to correctly configure the cog's blacklist. Just a small example would be enough.

Comment thread bot/services/random_name_service.py Outdated
:rtype: str
"""

name = f"{random.choice(_LEFT).capitalize()} {random.choice(_RIGHT).capitalize()}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: instead of calling .capitalize() on both name you could call .title() on the whole string.

@pytest.mark.asyncio
@patch("bot.extensions.name_moderation_cog.notice")
@patch("bot.extensions.name_moderation_cog.make_random_name")
async def test_name_moderation_on_member_join__with_blacklisted_name__expect_change_and_message(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: don't be afraid to go even more specific test_on_member_join__with_blacklisted_name__expect_changed_name_and_sends_message

@PenguinBoi12
PenguinBoi12 merged commit ef45510 into Code-Society-Lab:main Aug 1, 2026
2 checks passed
@Eyad-Jawad
Eyad-Jawad deleted the user-nickname-moderation branch August 2, 2026 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants