234 lines
8.3 KiB
Python
234 lines
8.3 KiB
Python
# modules/permissions.py
|
|
|
|
import json
|
|
import os
|
|
import globals
|
|
import discord
|
|
|
|
PERMISSIONS_FILE = "permissions.json"
|
|
TWITCH_CONFIG_FILE = "settings/twitch_channels_config.json"
|
|
|
|
##########################
|
|
# Load Configurations
|
|
##########################
|
|
|
|
def load_json_file(file_path):
|
|
"""Loads JSON data from a file, returns an empty dict if missing or invalid."""
|
|
if not os.path.exists(file_path):
|
|
return {}
|
|
try:
|
|
with open(file_path, "r", encoding="utf-8") as file:
|
|
return json.load(file)
|
|
except json.JSONDecodeError as e:
|
|
globals.log(f"Error parsing JSON file {file_path}: {e}", "ERROR")
|
|
return {}
|
|
|
|
def load_permissions():
|
|
"""Dynamically loads permissions from `permissions.json`."""
|
|
return load_json_file(PERMISSIONS_FILE)
|
|
|
|
def load_twitch_config():
|
|
"""Dynamically loads Twitch-specific command allow/deny lists."""
|
|
return load_json_file(TWITCH_CONFIG_FILE)
|
|
|
|
##########################
|
|
# Role Mapping
|
|
##########################
|
|
|
|
def map_roles(platform: str, user_roles: list, context_identifier: str = None) -> list:
|
|
"""
|
|
Maps platform-specific roles to a unified role system.
|
|
Supports per-guild (Discord) and per-channel (Twitch) overrides.
|
|
|
|
:param platform: "discord" or "twitch"
|
|
:param user_roles: List of raw roles/badges from the platform
|
|
:param context_identifier: Guild ID (for Discord) or Channel Name (for Twitch)
|
|
:return: List of mapped roles
|
|
"""
|
|
permissions = load_permissions()
|
|
role_mappings = permissions.get("role_mappings", {}).get(platform, {})
|
|
|
|
# Allow per-context overrides
|
|
if context_identifier:
|
|
specific_mappings = permissions.get("role_mappings", {}).get(f"{platform}_{context_identifier}", {})
|
|
role_mappings.update(specific_mappings) # Override defaults
|
|
|
|
mapped_roles = [role_mappings.get(role.lower(), role.lower()) for role in user_roles]
|
|
|
|
return list(set(mapped_roles)) if mapped_roles else ["everyone"]
|
|
|
|
##########################
|
|
# Permissions Checks
|
|
##########################
|
|
|
|
def has_permission(command_name: str, user_id: str, user_roles: list, platform: str, context_identifier: str = None) -> bool:
|
|
"""
|
|
Checks if a user has permission to execute a command.
|
|
|
|
:param command_name: The command to check
|
|
:param user_id: The user's ID
|
|
:param user_roles: The user's roles/badges
|
|
:param platform: "discord" or "twitch"
|
|
:param context_identifier: Guild ID (for Discord) or Channel Name (for Twitch)
|
|
:return: True if the user has permission, False otherwise
|
|
"""
|
|
permissions = load_permissions()
|
|
command_perms = permissions.get("commands", {}).get(command_name, {})
|
|
|
|
# Extract permission settings
|
|
min_role = command_perms.get("min_role", "")
|
|
allowed_roles = command_perms.get("allowed_roles", [])
|
|
allowed_users = command_perms.get("allowed_users", [])
|
|
|
|
# Auto-allow if no specific rules exist
|
|
if not min_role and not allowed_roles and not allowed_users:
|
|
return True
|
|
|
|
# Explicit user whitelist
|
|
if user_id in allowed_users:
|
|
return True
|
|
|
|
# Convert platform roles
|
|
mapped_roles = map_roles(platform, user_roles, context_identifier)
|
|
|
|
# Check minimum required role
|
|
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 explicitly allowed roles
|
|
if any(role in allowed_roles for role in mapped_roles):
|
|
return True
|
|
|
|
return False
|
|
|
|
##########################
|
|
# Twitch Command Filtering
|
|
##########################
|
|
|
|
def is_command_allowed_twitch(command_name: str, channel_name: str) -> bool:
|
|
"""
|
|
Checks if a command is allowed in a specific Twitch channel.
|
|
|
|
:param command_name: The command being checked
|
|
:param channel_name: The Twitch channel name
|
|
:return: True if allowed, False if blocked
|
|
"""
|
|
twitch_config = load_twitch_config()
|
|
channel_config = twitch_config.get(channel_name.lower(), {})
|
|
|
|
if not channel_config:
|
|
return False # Default to deny if no config exists
|
|
|
|
mode = channel_config.get("commands_filter_mode", "exclude")
|
|
filtered_commands = channel_config.get("commands_filtered", [])
|
|
|
|
if mode == "exclude" and command_name in filtered_commands:
|
|
return False
|
|
if mode == "include" and command_name not in filtered_commands:
|
|
return False
|
|
|
|
return True
|
|
|
|
# modules/permissions.py
|
|
|
|
# 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
|
|
|
|
|
|
def has_custom_vc_permission(member: discord.Member, vc_owner_id: int = None) -> bool:
|
|
"""
|
|
Checks if the given member is either the channel's owner (vc_owner_id)
|
|
or a recognized moderator (one of the roles in MODERATOR_ROLE_IDS).
|
|
Returns True if they can manage the channel, False otherwise.
|
|
"""
|
|
|
|
MODERATOR_ROLE_IDS = {
|
|
896715419681947650, # Pack Owner
|
|
1345410182674513920, # Pack Host
|
|
958415559370866709, # Discord-specific moderator
|
|
896715186357043200, # Pack-general moderator
|
|
}
|
|
|
|
# 1) Check if user is the “owner” of the channel
|
|
if vc_owner_id is not None and member.id == vc_owner_id:
|
|
return True
|
|
|
|
# 2) Check if the user has any of the allowed moderator roles
|
|
user_role_ids = {r.id for r in member.roles}
|
|
if MODERATOR_ROLE_IDS.intersection(user_role_ids):
|
|
return True
|
|
|
|
# Otherwise, no permission
|
|
return False |