Refactor code structure for improved readability and maintainability

This commit is contained in:
Slipstream 2025-05-30 18:09:05 -06:00
parent 28960c4c0c
commit a3eacbcfe0
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
3 changed files with 801 additions and 411 deletions

View File

@ -76,6 +76,50 @@ class UserSettings(BaseModel):
# Last updated timestamp
last_updated: datetime.datetime = Field(default_factory=datetime.datetime.now)
# ============= Role Selector Models =============
class RoleOption(BaseModel):
"""Represents a single selectable role within a category preset."""
role_id: str # Discord Role ID
name: str
emoji: Optional[str] = None
class RoleCategoryPreset(BaseModel):
"""Represents a global preset for a role category."""
id: str = Field(default_factory=lambda: str(uuid.uuid4())) # Unique ID for the preset category
name: str # e.g., "Colors", "Pronouns"
description: str
roles: List[RoleOption] = []
max_selectable: int = 1
display_order: int = 0 # For ordering presets if listed
class GuildRole(BaseModel):
"""Represents a specific role configured by a guild for selection."""
role_id: str # Discord Role ID
name: str
emoji: Optional[str] = None
class GuildRoleCategoryConfig(BaseModel):
"""Represents a guild's specific configuration for a role selection category."""
guild_id: str
category_id: str = Field(default_factory=lambda: str(uuid.uuid4())) # Unique ID for this guild's category instance
name: str # Custom name or preset name
description: str
roles: List[GuildRole] = []
max_selectable: int = 1
message_id: Optional[str] = None # Discord message ID of the selector embed
channel_id: Optional[str] = None # Discord channel ID where the selector embed is posted
is_preset: bool = False # True if this category is based on a global preset
preset_id: Optional[str] = None # If is_preset, this links to RoleCategoryPreset.id
class UserCustomColorRole(BaseModel):
"""Represents a user's custom color role."""
user_id: str
guild_id: str
role_id: str # Discord Role ID of their custom color role
hex_color: str # e.g., "#RRGGBB"
last_updated: datetime.datetime = Field(default_factory=datetime.datetime.now)
# ============= API Request/Response Models =============
class GetConversationsResponse(BaseModel):

View File

@ -3,7 +3,10 @@ import json
import datetime
from typing import Dict, List, Optional, Any
# Use absolute import for api_models
from api_service.api_models import Conversation, UserSettings, Message
from api_service.api_models import (
Conversation, UserSettings, Message,
RoleCategoryPreset, GuildRoleCategoryConfig, UserCustomColorRole
)
# ============= Database Class =============
@ -13,6 +16,9 @@ class Database:
self.conversations_file = os.path.join(data_dir, "conversations.json")
self.settings_file = os.path.join(data_dir, "user_settings.json")
self.tokens_file = os.path.join(data_dir, "user_tokens.json")
self.role_presets_file = os.path.join(data_dir, "role_category_presets.json")
self.guild_role_configs_file = os.path.join(data_dir, "guild_role_category_configs.json")
self.user_color_roles_file = os.path.join(data_dir, "user_custom_color_roles.json")
# Create data directory if it doesn't exist
os.makedirs(data_dir, exist_ok=True)
@ -21,6 +27,10 @@ class Database:
self.conversations: Dict[str, Dict[str, Conversation]] = {} # user_id -> conversation_id -> Conversation
self.user_settings: Dict[str, UserSettings] = {} # user_id -> UserSettings
self.user_tokens: Dict[str, Dict[str, Any]] = {} # user_id -> token_data
self.role_category_presets: Dict[str, RoleCategoryPreset] = {} # preset_id -> RoleCategoryPreset
self.guild_role_category_configs: Dict[str, List[GuildRoleCategoryConfig]] = {} # guild_id -> List[GuildRoleCategoryConfig]
self.user_custom_color_roles: Dict[str, Dict[str, UserCustomColorRole]] = {} # guild_id -> user_id -> UserCustomColorRole
# Load data from files
self.load_data()
@ -30,12 +40,115 @@ class Database:
self.load_conversations()
self.load_user_settings()
self.load_user_tokens()
self.load_role_category_presets()
self.load_guild_role_category_configs()
self.load_user_custom_color_roles()
def save_data(self):
"""Save all data to files"""
self.save_conversations()
self.save_all_user_settings()
self.save_user_tokens()
self.save_role_category_presets()
self.save_guild_role_category_configs()
self.save_user_custom_color_roles()
# ============= Role Selector Data Load/Save Methods =============
def load_role_category_presets(self):
"""Load role category presets from file"""
if os.path.exists(self.role_presets_file):
try:
with open(self.role_presets_file, "r", encoding="utf-8") as f:
data = json.load(f)
self.role_category_presets = {
preset_id: RoleCategoryPreset.model_validate(preset_data)
for preset_id, preset_data in data.items()
}
print(f"Loaded {len(self.role_category_presets)} role category presets.")
except Exception as e:
print(f"Error loading role category presets: {e}")
self.role_category_presets = {}
else:
self.role_category_presets = {} # Initialize if file doesn't exist
def save_role_category_presets(self):
"""Save role category presets to file"""
try:
serializable_data = {
preset_id: preset.model_dump()
for preset_id, preset in self.role_category_presets.items()
}
with open(self.role_presets_file, "w", encoding="utf-8") as f:
json.dump(serializable_data, f, indent=2, default=str, ensure_ascii=False)
except Exception as e:
print(f"Error saving role category presets: {e}")
def load_guild_role_category_configs(self):
"""Load guild role category configs from file"""
if os.path.exists(self.guild_role_configs_file):
try:
with open(self.guild_role_configs_file, "r", encoding="utf-8") as f:
data = json.load(f)
self.guild_role_category_configs = {
guild_id: [GuildRoleCategoryConfig.model_validate(config_data) for config_data in configs_list]
for guild_id, configs_list in data.items()
}
print(f"Loaded guild role category configs for {len(self.guild_role_category_configs)} guilds.")
except Exception as e:
print(f"Error loading guild role category configs: {e}")
self.guild_role_category_configs = {}
else:
self.guild_role_category_configs = {}
def save_guild_role_category_configs(self):
"""Save guild role category configs to file"""
try:
serializable_data = {
guild_id: [config.model_dump() for config in configs_list]
for guild_id, configs_list in self.guild_role_category_configs.items()
}
with open(self.guild_role_configs_file, "w", encoding="utf-8") as f:
json.dump(serializable_data, f, indent=2, default=str, ensure_ascii=False)
except Exception as e:
print(f"Error saving guild role category configs: {e}")
def load_user_custom_color_roles(self):
"""Load user custom color roles from file"""
if os.path.exists(self.user_color_roles_file):
try:
with open(self.user_color_roles_file, "r", encoding="utf-8") as f:
data = json.load(f)
self.user_custom_color_roles = {
guild_id: {
user_id: UserCustomColorRole.model_validate(role_data)
for user_id, role_data in user_roles.items()
}
for guild_id, user_roles in data.items()
}
print(f"Loaded user custom color roles for {len(self.user_custom_color_roles)} guilds.")
except Exception as e:
print(f"Error loading user custom color roles: {e}")
self.user_custom_color_roles = {}
else:
self.user_custom_color_roles = {}
def save_user_custom_color_roles(self):
"""Save user custom color roles to file"""
try:
serializable_data = {
guild_id: {
user_id: role.model_dump()
for user_id, role in user_roles.items()
}
for guild_id, user_roles in self.user_custom_color_roles.items()
}
with open(self.user_color_roles_file, "w", encoding="utf-8") as f:
json.dump(serializable_data, f, indent=2, default=str, ensure_ascii=False)
except Exception as e:
print(f"Error saving user custom color roles: {e}")
# ============= Existing Data Load/Save Methods =============
def load_conversations(self):
"""Load conversations from file"""
@ -136,6 +249,98 @@ class Database:
return True
return False
# ============= Role Category Preset Methods =============
def get_role_category_preset(self, preset_id: str) -> Optional[RoleCategoryPreset]:
"""Get a specific role category preset by ID."""
return self.role_category_presets.get(preset_id)
def get_all_role_category_presets(self) -> List[RoleCategoryPreset]:
"""Get all role category presets."""
return list(self.role_category_presets.values())
def save_role_category_preset(self, preset: RoleCategoryPreset) -> RoleCategoryPreset:
"""Save a role category preset."""
self.role_category_presets[preset.id] = preset
self.save_role_category_presets()
return preset
def delete_role_category_preset(self, preset_id: str) -> bool:
"""Delete a role category preset."""
if preset_id in self.role_category_presets:
del self.role_category_presets[preset_id]
self.save_role_category_presets()
return True
return False
# ============= Guild Role Category Config Methods =============
def get_guild_role_category_configs(self, guild_id: str) -> List[GuildRoleCategoryConfig]:
"""Get all role category configurations for a specific guild."""
return self.guild_role_category_configs.get(guild_id, [])
def get_all_guild_role_category_configs(self) -> Dict[str, List[GuildRoleCategoryConfig]]:
"""Get all role category configurations for all guilds."""
return self.guild_role_category_configs
def get_guild_role_category_config(self, guild_id: str, category_id: str) -> Optional[GuildRoleCategoryConfig]:
"""Get a specific role category configuration for a guild."""
for config in self.get_guild_role_category_configs(guild_id):
if config.category_id == category_id:
return config
return None
def save_guild_role_category_config(self, config: GuildRoleCategoryConfig) -> GuildRoleCategoryConfig:
"""Save a guild's role category configuration."""
guild_id = config.guild_id
if guild_id not in self.guild_role_category_configs:
self.guild_role_category_configs[guild_id] = []
# Remove existing config with the same category_id if it exists, then add the new/updated one
self.guild_role_category_configs[guild_id] = [c for c in self.guild_role_category_configs[guild_id] if c.category_id != config.category_id]
self.guild_role_category_configs[guild_id].append(config)
self.save_guild_role_category_configs()
return config
def delete_guild_role_category_config(self, guild_id: str, category_id: str) -> bool:
"""Delete a specific role category configuration for a guild."""
if guild_id in self.guild_role_category_configs:
initial_len = len(self.guild_role_category_configs[guild_id])
self.guild_role_category_configs[guild_id] = [
c for c in self.guild_role_category_configs[guild_id] if c.category_id != category_id
]
if len(self.guild_role_category_configs[guild_id]) < initial_len:
self.save_guild_role_category_configs()
return True
return False
# ============= User Custom Color Role Methods =============
def get_user_custom_color_role(self, guild_id: str, user_id: str) -> Optional[UserCustomColorRole]:
"""Get a user's custom color role in a specific guild."""
return self.user_custom_color_roles.get(guild_id, {}).get(user_id)
def save_user_custom_color_role(self, color_role: UserCustomColorRole) -> UserCustomColorRole:
"""Save a user's custom color role."""
guild_id = color_role.guild_id
user_id = color_role.user_id
if guild_id not in self.user_custom_color_roles:
self.user_custom_color_roles[guild_id] = {}
color_role.last_updated = datetime.datetime.now()
self.user_custom_color_roles[guild_id][user_id] = color_role
self.save_user_custom_color_roles()
return color_role
def delete_user_custom_color_role(self, guild_id: str, user_id: str) -> bool:
"""Delete a user's custom color role in a specific guild."""
if guild_id in self.user_custom_color_roles and user_id in self.user_custom_color_roles[guild_id]:
del self.user_custom_color_roles[guild_id][user_id]
self.save_user_custom_color_roles()
return True
return False
# ============= User Settings Methods =============
def get_user_settings(self, user_id: str) -> UserSettings:

File diff suppressed because it is too large Load Diff