Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
- chore: Split functions into separate files
- chore: replace JS-like filters and maps with list comprehensions
- chore: make better logging and error handling
- fix: Add members intent to avoid deleting in-use roles
  • Loading branch information
rwbxd committed Oct 13, 2024
1 parent 1fd92a0 commit 7ec83e4
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 59 deletions.
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.venv
.venv
.github
.gitignore
73 changes: 15 additions & 58 deletions bot.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import discord
import colour
import discord.guild
import os
import sys
import re
from create import color_user
from manage import clean_empty_color_roles

intents = discord.Intents.default()
intents.members = True

guild_ids = sys.argv[1:]
bot = discord.Bot()
bot = discord.Bot(intents=intents)


@bot.event
async def on_ready():
print("Palette Bot is up!")
print(f"We have logged in as {bot.user}")


@bot.slash_command(description="Give your name a random color", guild_ids=guild_ids)
async def colormerandom(ctx: discord.ApplicationContext):
await color_user(ctx, ctx.user, os.urandom(3).hex())
Expand All @@ -23,61 +27,14 @@ async def colorme(ctx: discord.ApplicationContext, color: str):
await color_user(ctx, ctx.user, color)


async def color_user(
ctx: discord.ApplicationContext, user, color: str
):
color = color.strip().replace(" ", "")
if re.search("^[a-f0-9]{3}$|^[a-f0-9]{6}$", color, re.IGNORECASE):
color = "#" + color

try:
role_color = colour.Color(color)
except ValueError:
await ctx.respond(
f"Didn't recognize color: {color} - try something else, or a specific hex code!"
)
return
print(f"Coloring {user.name} the color {role_color.web} ({role_color.get_hex()})")
color_roles: list[discord.Role] = list(
filter(lambda role: role.name.startswith("#"), ctx.guild.roles)
)
current_role = next(
filter(lambda role: role.name == role_color.get_hex(), color_roles), None
)
if not current_role:
current_role = await new_role(ctx.guild, role_color)

await user.remove_roles(*color_roles)
await user.add_roles(current_role)
await ctx.respond(f"Colored you {role_color.web}!")


async def new_role(guild: discord.Guild, color: colour.Color):
new_role = await guild.create_role(
name=color.get_hex(),
color=discord.Color.from_rgb(
int(color.get_red() * 255),
int(color.get_green() * 255),
int(color.get_blue() * 255),
),
)
return await new_role.edit(
position=max(map(lambda rule: rule.position, guild.me.roles)) - 2
)


@bot.slash_command(description="Clean unused colors", guild_ids=guild_ids)
async def cleanbrushes(ctx: discord.ApplicationContext):
empty_color_roles = filter(
lambda role: role.name.startswith("#") and len(role.members) == 0,
ctx.guild.roles,
)
for role in empty_color_roles:
try:
await role.delete()
except:
pass
await ctx.respond("Cleaned up all empty color roles!")
await clean_empty_color_roles(ctx)


bot.run(os.environ.get("DISCORD_TOKEN", "DISCORDTOKENNOTFOUND"))
bot.run(
os.environ.get(
"DISCORD_TOKEN",
"DISCORD_TOKEN_NOT_FOUND",
)
)
47 changes: 47 additions & 0 deletions create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import discord
import re
import colour
from util import create_new_role, errorAndRespond, logInfo


async def color_user(
ctx: discord.ApplicationContext, user: discord.Member | discord.User, color: str
):
try:
assert (
type(ctx.guild) is discord.Guild
), "Encountered an issue accessing the Discord guild"

color = color.strip().replace(" ", "")
if re.search("^[a-f0-9]{3}$|^[a-f0-9]{6}$", color, re.IGNORECASE):
color = "#" + color

try:
role_color = colour.Color(color)
except ValueError:
return await ctx.respond(
f"Didn't recognize color: {color} - try something else, or a specific hex code!"
)

logInfo(
f"Coloring {user.name} the color {role_color.web} ({role_color.get_hex()})"
)

all_color_roles: list[discord.Role] = [
role for role in ctx.guild.roles if role.name.startswith("#")
]
desired_color_role = next(
(role for role in all_color_roles if role.name == role_color.get_hex()),
None,
) or await create_new_role(ctx.guild, role_color)
if desired_color_role is None:
return await errorAndRespond(
ctx, f"Failed to create new role for color: {color}"
)

await user.remove_roles(*all_color_roles)
await user.add_roles(desired_color_role)
return await ctx.respond(f"Colored you {role_color.web}!")

except AssertionError as errorMessage:
return await errorAndRespond(ctx, errorMessage)
24 changes: 24 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import discord
from util import errorAndRespond, logAndRespond, logError


async def clean_empty_color_roles(ctx: discord.ApplicationContext):
try:
assert (
type(ctx.guild) is discord.Guild
), "Encountered an issue accessing the Discord guild"
empty_color_roles = [
role
for role in ctx.guild.roles
if role.name.startswith("#") and len(role.members) == 0
]
counter = 0
for role in empty_color_roles:
try:
await role.delete()
counter += 1
except:
logError(f"Failed to delete role {role.name}")
return await logAndRespond(ctx, f"Cleaned up {counter} empty color roles!")
except AssertionError as errorMessage:
return await errorAndRespond(ctx, errorMessage)
Empty file added modify.py
Empty file.
46 changes: 46 additions & 0 deletions util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import discord
import colour


async def create_new_role(
guild: discord.Guild, color: colour.Color
) -> discord.Role | None:
try:
new_role = await guild.create_role(
name=color.get_hex(),
color=discord.Color.from_rgb(
int(color.get_red() * 255),
int(color.get_green() * 255),
int(color.get_blue() * 255),
),
)
logInfo(f"Successfully created new role {color.get_hex()}")
except (discord.Forbidden, discord.HTTPException, discord.InvalidArgument) as e:
logError(f"Failed to create role {color.get_hex()} with {e.text}")
return None

try:
return await new_role.edit(
position=max([role.position for role in guild.me.roles]) - 2
)
except (discord.Forbidden, discord.HTTPException, discord.InvalidArgument) as e:
logError(f"Failed to move role {color.get_hex()} with {e.text}")
return new_role


async def errorAndRespond(ctx: discord.ApplicationContext, message: str):
logError(message)
return await ctx.respond(f"{message}, please try again in a few seconds")


async def logAndRespond(ctx: discord.ApplicationContext, message: str):
logInfo(message)
return await ctx.respond(message)


def logError(message: str):
print(f"ERROR: {message}")


def logInfo(message: str):
print(f"INFO: {message}")

0 comments on commit 7ec83e4

Please sign in to comment.