diff --git a/bot_twitch.py b/bot_twitch.py index fc24402..54a4059 100644 --- a/bot_twitch.py +++ b/bot_twitch.py @@ -22,6 +22,8 @@ class TwitchBot(commands.Bot): initial_channels=config["twitch_channels"] ) + self.log("Twitch bot initiated", "INFO") + # 2) Then load commands self.load_commands() diff --git a/cmd_common/common_commands.py b/cmd_common/common_commands.py index c223b87..cf0175f 100644 --- a/cmd_common/common_commands.py +++ b/cmd_common/common_commands.py @@ -4,7 +4,7 @@ import time from modules import utility import globals -def generate_howl_message(username: str) -> str: +def howl(username: str) -> str: """ Return a random howl message (0-100). - If 0%: a fail message. diff --git a/cmd_discord.py b/cmd_discord.py index 200d5fc..c8489c2 100644 --- a/cmd_discord.py +++ b/cmd_discord.py @@ -1,6 +1,7 @@ # cmd_discord.py from discord.ext import commands from cmd_common import common_commands as cc +from modules.permissions import has_permission def setup(bot): @bot.command() @@ -16,7 +17,7 @@ def setup(bot): @bot.command() async def howl(ctx): """Calls the shared !howl logic.""" - result = cc.generate_howl_message(ctx.author.display_name) + result = cc.howl(ctx.author.display_name) await ctx.send(result) @bot.command() @@ -30,3 +31,14 @@ def setup(bot): await ctx.send("Commands reloaded!") except Exception as e: await ctx.send(f"Error reloading commands: {e}") + + @bot.command() + async def hi(ctx): + user_id = str(ctx.author.id) + user_roles = [role.name.lower() for role in ctx.author.roles] # Normalize to lowercase + + if not has_permission("hi", user_id, user_roles, "discord"): + await ctx.send("You don't have permission to use this command.") + return + + await ctx.send("Hello there!") \ No newline at end of file diff --git a/cmd_twitch.py b/cmd_twitch.py index 2c8c520..aa7c97e 100644 --- a/cmd_twitch.py +++ b/cmd_twitch.py @@ -1,6 +1,7 @@ # cmd_twitch.py from twitchio.ext import commands from cmd_common import common_commands as cc +from modules.permissions import has_permission def setup(bot): @bot.command(name="greet") @@ -14,6 +15,17 @@ def setup(bot): await ctx.send(result) @bot.command(name="howl") - async def howl_command(ctx): - result = cc.generate_howl_message(ctx.author.display_name) + async def howl(ctx): + result = cc.howl(ctx.author.display_name) await ctx.send(result) + + @bot.command(name="hi") + async def hi_command(ctx): + user_id = str(ctx.author.id) # Twitch user ID + user_roles = [role.lower() for role in ctx.author.badges.keys()] # Use Twitch badges as roles + + if not has_permission("hi", user_id, user_roles, "twitch"): + await ctx.send("You don't have permission to use this command.") + return + + await ctx.send("Hello there!") \ No newline at end of file diff --git a/modules/permissions.py b/modules/permissions.py new file mode 100644 index 0000000..b350596 --- /dev/null +++ b/modules/permissions.py @@ -0,0 +1,75 @@ +import json +import os + +PERMISSIONS_FILE = "permissions.json" + +# Load permission settings +def load_permissions(): + """Loads the permissions from JSON.""" + if not os.path.exists(PERMISSIONS_FILE): + return {} + with open(PERMISSIONS_FILE, "r", encoding="utf-8") as file: + return json.load(file) + +def map_roles(platform: str, user_roles: list) -> list: + """ + Maps platform-specific roles to a unified role system. + + :param platform: "discord" or "twitch" + :param user_roles: A list of raw roles/badges from the platform + :return: A list of mapped roles based on the JSON role mapping + """ + permissions = load_permissions() + role_mappings = permissions.get("role_mappings", {}).get(platform, {}) + + mapped_roles = [] + for role in user_roles: + normalized_role = role.lower() + mapped_role = role_mappings.get(normalized_role, None) + if mapped_role: + mapped_roles.append(mapped_role) + + return mapped_roles if mapped_roles else ["everyone"] + +def has_permission(command_name: str, user_id: str, user_roles: list, platform: str) -> bool: + """ + Checks if a user has permission to run a command. + + :param command_name: The name of the command being checked. + :param user_id: The ID of the user requesting the command. + :param user_roles: A list of roles/badges the user has (platform-specific). + :param platform: "discord" or "twitch" + :return: True if the user has permission, otherwise False. + """ + permissions = load_permissions() + command_perms = permissions.get("commands", {}).get(command_name, {}) + + # Extract settings + min_role = command_perms.get("min_role", "") + allowed_roles = command_perms.get("allowed_roles", []) + allowed_users = command_perms.get("allowed_users", []) + + # If no min_role and no allowed_roles/users, it's open to everyone + if not min_role and not allowed_roles and not allowed_users: + return True + + # Check if user is explicitly allowed + if user_id in allowed_users: + return True # Bypass role check + + # Convert platform-specific roles to mapped roles + mapped_roles = map_roles(platform, user_roles) + + # If a min_role is set, check against it + if min_role: + role_hierarchy = ["everyone", "follower", "subscriber", "vip", "moderator", "admin", "owner"] + user_role_level = max([role_hierarchy.index(role) for role in mapped_roles if role in role_hierarchy], default=0) + min_role_level = role_hierarchy.index(min_role) if min_role in role_hierarchy else 0 + if user_role_level >= min_role_level: + return True + + # Check if the user has any explicitly allowed roles + if any(role in allowed_roles for role in mapped_roles): + return True + + return False diff --git a/permissions.json b/permissions.json new file mode 100644 index 0000000..39d7141 --- /dev/null +++ b/permissions.json @@ -0,0 +1,24 @@ +{ + "role_mappings": { + "twitch": { + "moderator": "moderator", + "vip": "vip", + "subscriber": "subscriber", + "follower": "follower", + "broadcaster": "owner" + }, + "discord": { + "pack mods": "moderator", + "trusted pack member": "vip", + "subscriber": "subscriber", + "everyone": "everyone" + } + }, + "commands": { + "hi": { + "min_role": "", + "allowed_roles": [], + "allowed_users": [] + } + } +}