fixed imports again

This commit is contained in:
pacnpal
2024-11-18 01:21:40 +00:00
parent d03e8dc8e8
commit fc06e54d8a
37 changed files with 879 additions and 882 deletions

View File

@@ -1,49 +1,50 @@
"""Configuration management module"""
try:
# Try relative imports first
from .exceptions import (
ConfigurationError,
ValidationError,
PermissionError,
LoadError,
SaveError,
MigrationError,
SchemaError,
DiscordAPIError,
)
from .channel_manager import ChannelManager
from .role_manager import RoleManager
from .settings_formatter import SettingsFormatter
from .validation_manager import ValidationManager
except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import (
ConfigurationError,
ValidationError,
PermissionError,
LoadError,
SaveError,
MigrationError,
SchemaError,
DiscordAPIError,
)
# from videoarchiver.config.channel_manager import ChannelManager
# from videoarchiver.config.role_manager import RoleManager
# from videoarchiver.config.settings_formatter import SettingsFormatter
# from videoarchiver.config.validation_manager import ValidationManager
# try:
# Try relative imports first
from .exceptions import (
ConfigurationError,
ValidationError,
PermissionError,
LoadError,
SaveError,
MigrationError,
SchemaError,
DiscordAPIError,
)
from .channel_manager import ChannelManager
from .role_manager import RoleManager
from .settings_formatter import SettingsFormatter
from .validation_manager import ValidationManager
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import (
# ConfigurationError,
# ValidationError,
# PermissionError,
# LoadError,
# SaveError,
# MigrationError,
# SchemaError,
# DiscordAPIError,
# )
# from videoarchiver.config.channel_manager import ChannelManager
# from videoarchiver.config.role_manager import RoleManager
# from videoarchiver.config.settings_formatter import SettingsFormatter
# from videoarchiver.config.validation_manager import ValidationManager
__all__ = [
'ConfigurationError',
'ValidationError',
'PermissionError',
'LoadError',
'SaveError',
'MigrationError',
'SchemaError',
'DiscordAPIError',
'ChannelManager',
'RoleManager',
'SettingsFormatter',
'ValidationManager',
"ConfigurationError",
"ValidationError",
"PermissionError",
"LoadError",
"SaveError",
"MigrationError",
"SchemaError",
"DiscordAPIError",
"ChannelManager",
"RoleManager",
"SettingsFormatter",
"ValidationManager",
]

View File

@@ -2,20 +2,21 @@
import logging
from typing import Dict, List, Optional, Tuple
import discord # type: ignore
import discord # type: ignore
try:
# Try relative imports first
from .exceptions import (
ConfigurationError as ConfigError,
DiscordAPIError,
)
except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import (
ConfigurationError as ConfigError,
DiscordAPIError,
)
# try:
# Try relative imports first
from .exceptions import (
ConfigurationError as ConfigError,
DiscordAPIError,
)
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import (
# ConfigurationError as ConfigError,
# DiscordAPIError,
# )
logger = logging.getLogger("ChannelManager")

View File

@@ -2,14 +2,15 @@
import logging
from typing import Dict, List, Set, Tuple, Optional, Any
import discord # type: ignore
import discord # type: ignore
try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
logger = logging.getLogger("RoleManager")
@@ -21,26 +22,24 @@ class RoleManager:
self.config_manager = config_manager
async def check_user_roles(
self,
member: discord.Member
self, member: discord.Member
) -> Tuple[bool, Optional[str]]:
"""Check if user has permission based on allowed roles
Args:
member: Discord member to check
Returns:
Tuple[bool, Optional[str]]: (Has permission, Reason if denied)
Raises:
ConfigError: If role check fails
"""
try:
allowed_roles = await self.config_manager.get_setting(
member.guild.id,
"allowed_roles"
member.guild.id, "allowed_roles"
)
# If no roles are set, allow all users
if not allowed_roles:
return True, None
@@ -48,91 +47,73 @@ class RoleManager:
# Check user roles
user_roles = {role.id for role in member.roles}
allowed_role_set = set(allowed_roles)
if user_roles & allowed_role_set: # Intersection
return True, None
# Get role names for error message
missing_roles = await self._get_role_names(
member.guild,
allowed_role_set
)
missing_roles = await self._get_role_names(member.guild, allowed_role_set)
return False, f"Missing required roles: {', '.join(missing_roles)}"
except Exception as e:
logger.error(f"Failed to check roles for user {member.id} in guild {member.guild.id}: {e}")
logger.error(
f"Failed to check roles for user {member.id} in guild {member.guild.id}: {e}"
)
raise ConfigError(f"Failed to check user roles: {str(e)}")
async def add_allowed_role(
self,
guild_id: int,
role_id: int
) -> None:
async def add_allowed_role(self, guild_id: int, role_id: int) -> None:
"""Add a role to allowed roles
Args:
guild_id: Guild ID
role_id: Role ID to add
Raises:
ConfigError: If role cannot be added
"""
try:
await self.config_manager.add_to_list(
guild_id,
"allowed_roles",
role_id
)
await self.config_manager.add_to_list(guild_id, "allowed_roles", role_id)
except Exception as e:
logger.error(f"Failed to add allowed role {role_id}: {e}")
raise ConfigError(f"Failed to add allowed role: {str(e)}")
async def remove_allowed_role(
self,
guild_id: int,
role_id: int
) -> None:
async def remove_allowed_role(self, guild_id: int, role_id: int) -> None:
"""Remove a role from allowed roles
Args:
guild_id: Guild ID
role_id: Role ID to remove
Raises:
ConfigError: If role cannot be removed
"""
try:
await self.config_manager.remove_from_list(
guild_id,
"allowed_roles",
role_id
guild_id, "allowed_roles", role_id
)
except Exception as e:
logger.error(f"Failed to remove allowed role {role_id}: {e}")
raise ConfigError(f"Failed to remove allowed role: {str(e)}")
async def get_allowed_roles(
self,
guild: discord.Guild
) -> List[discord.Role]:
async def get_allowed_roles(self, guild: discord.Guild) -> List[discord.Role]:
"""Get all allowed roles for a guild
Args:
guild: Discord guild
Returns:
List[discord.Role]: List of allowed roles
Raises:
ConfigError: If roles cannot be retrieved
"""
try:
settings = await self.config_manager.get_guild_settings(guild.id)
role_ids = settings["allowed_roles"]
roles = []
invalid_roles = []
for role_id in role_ids:
role = guild.get_role(role_id)
if role:
@@ -140,55 +121,54 @@ class RoleManager:
else:
invalid_roles.append(role_id)
logger.warning(f"Invalid role {role_id} in guild {guild.id}")
# Clean up invalid roles if found
if invalid_roles:
await self._remove_invalid_roles(guild.id, invalid_roles)
return roles
except Exception as e:
logger.error(f"Failed to get allowed roles for guild {guild.id}: {e}")
raise ConfigError(f"Failed to get allowed roles: {str(e)}")
async def verify_role_hierarchy(
self,
guild: discord.Guild,
role: discord.Role
self, guild: discord.Guild, role: discord.Role
) -> Tuple[bool, Optional[str]]:
"""Verify bot's role hierarchy position for managing a role
Args:
guild: Discord guild
role: Role to check
Returns:
Tuple[bool, Optional[str]]: (Can manage role, Reason if not)
"""
try:
bot_member = guild.me
bot_top_role = bot_member.top_role
if role >= bot_top_role:
return False, f"Role {role.name} is higher than or equal to bot's highest role"
return (
False,
f"Role {role.name} is higher than or equal to bot's highest role",
)
return True, None
except Exception as e:
logger.error(f"Error checking role hierarchy: {e}")
return False, "Failed to check role hierarchy"
async def _get_role_names(
self,
guild: discord.Guild,
role_ids: Set[int]
self, guild: discord.Guild, role_ids: Set[int]
) -> List[str]:
"""Get role names from role IDs
Args:
guild: Discord guild
role_ids: Set of role IDs
Returns:
List[str]: List of role names
"""
@@ -199,13 +179,9 @@ class RoleManager:
role_names.append(role.name)
return role_names
async def _remove_invalid_roles(
self,
guild_id: int,
role_ids: List[int]
) -> None:
async def _remove_invalid_roles(self, guild_id: int, role_ids: List[int]) -> None:
"""Remove invalid roles from allowed roles
Args:
guild_id: Guild ID
role_ids: List of invalid role IDs to remove
@@ -216,33 +192,30 @@ class RoleManager:
except Exception as e:
logger.error(f"Error removing invalid roles: {e}")
async def get_role_info(
self,
guild: discord.Guild
) -> Dict[str, Any]:
async def get_role_info(self, guild: discord.Guild) -> Dict[str, Any]:
"""Get role configuration information
Args:
guild: Discord guild
Returns:
Dict[str, Any]: Dictionary containing role information
"""
try:
allowed_roles = await self.get_allowed_roles(guild)
bot_member = guild.me
return {
'allowed_roles': allowed_roles,
'bot_top_role': bot_member.top_role,
'bot_permissions': bot_member.guild_permissions,
'role_count': len(allowed_roles)
"allowed_roles": allowed_roles,
"bot_top_role": bot_member.top_role,
"bot_permissions": bot_member.guild_permissions,
"role_count": len(allowed_roles),
}
except Exception as e:
logger.error(f"Error getting role info: {e}")
return {
'allowed_roles': [],
'bot_top_role': None,
'bot_permissions': None,
'role_count': 0
"allowed_roles": [],
"bot_top_role": None,
"bot_permissions": None,
"role_count": 0,
}

View File

@@ -3,14 +3,15 @@
import logging
from typing import Dict, Any, List
from datetime import datetime
import discord # type: ignore
import discord # type: ignore
try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
logger = logging.getLogger("SettingsFormatter")
@@ -22,19 +23,17 @@ class SettingsFormatter:
self.embed_color = discord.Color.blue()
async def format_settings_embed(
self,
guild: discord.Guild,
settings: Dict[str, Any]
self, guild: discord.Guild, settings: Dict[str, Any]
) -> discord.Embed:
"""Format guild settings into a Discord embed
Args:
guild: Discord guild
settings: Guild settings dictionary
Returns:
discord.Embed: Formatted settings embed
Raises:
ConfigError: If formatting fails
"""
@@ -42,7 +41,7 @@ class SettingsFormatter:
embed = discord.Embed(
title="Video Archiver Settings",
color=self.embed_color,
timestamp=datetime.utcnow()
timestamp=datetime.utcnow(),
)
# Add sections
@@ -61,111 +60,98 @@ class SettingsFormatter:
raise ConfigError(f"Failed to format settings: {str(e)}")
async def _add_core_settings(
self,
embed: discord.Embed,
guild: discord.Guild,
settings: Dict[str, Any]
self, embed: discord.Embed, guild: discord.Guild, settings: Dict[str, Any]
) -> None:
"""Add core settings to embed"""
embed.add_field(
name="Core Settings",
value="\n".join([
f"**Enabled:** {settings['enabled']}",
f"**Database Enabled:** {settings['use_database']}",
f"**Update Check Disabled:** {settings['disable_update_check']}"
]),
inline=False
value="\n".join(
[
f"**Enabled:** {settings['enabled']}",
f"**Database Enabled:** {settings['use_database']}",
f"**Update Check Disabled:** {settings['disable_update_check']}",
]
),
inline=False,
)
async def _add_channel_settings(
self,
embed: discord.Embed,
guild: discord.Guild,
settings: Dict[str, Any]
self, embed: discord.Embed, guild: discord.Guild, settings: Dict[str, Any]
) -> None:
"""Add channel settings to embed"""
# Get channels with error handling
channels = await self._get_channel_mentions(guild, settings)
embed.add_field(
name="Channel Settings",
value="\n".join([
f"**Archive Channel:** {channels['archive']}",
f"**Notification Channel:** {channels['notification']}",
f"**Log Channel:** {channels['log']}",
f"**Monitored Channels:**\n{channels['monitored']}"
]),
inline=False
value="\n".join(
[
f"**Archive Channel:** {channels['archive']}",
f"**Notification Channel:** {channels['notification']}",
f"**Log Channel:** {channels['log']}",
f"**Monitored Channels:**\n{channels['monitored']}",
]
),
inline=False,
)
async def _add_permission_settings(
self,
embed: discord.Embed,
guild: discord.Guild,
settings: Dict[str, Any]
self, embed: discord.Embed, guild: discord.Guild, settings: Dict[str, Any]
) -> None:
"""Add permission settings to embed"""
allowed_roles = await self._get_role_names(guild, settings["allowed_roles"])
embed.add_field(
name="Permission Settings",
value=f"**Allowed Roles:**\n{allowed_roles}",
inline=False
inline=False,
)
async def _add_video_settings(
self,
embed: discord.Embed,
settings: Dict[str, Any]
self, embed: discord.Embed, settings: Dict[str, Any]
) -> None:
"""Add video settings to embed"""
embed.add_field(
name="Video Settings",
value="\n".join([
f"**Format:** {settings['video_format']}",
f"**Max Quality:** {settings['video_quality']}p",
f"**Max File Size:** {settings['max_file_size']}MB"
]),
inline=False
value="\n".join(
[
f"**Format:** {settings['video_format']}",
f"**Max Quality:** {settings['video_quality']}p",
f"**Max File Size:** {settings['max_file_size']}MB",
]
),
inline=False,
)
async def _add_operation_settings(
self,
embed: discord.Embed,
settings: Dict[str, Any]
self, embed: discord.Embed, settings: Dict[str, Any]
) -> None:
"""Add operation settings to embed"""
embed.add_field(
name="Operation Settings",
value="\n".join([
f"**Delete After Repost:** {settings['delete_after_repost']}",
f"**Message Duration:** {settings['message_duration']} hours",
f"**Concurrent Downloads:** {settings['concurrent_downloads']}",
f"**Max Retries:** {settings['max_retries']}",
f"**Retry Delay:** {settings['retry_delay']}s"
]),
inline=False
value="\n".join(
[
f"**Delete After Repost:** {settings['delete_after_repost']}",
f"**Message Duration:** {settings['message_duration']} hours",
f"**Concurrent Downloads:** {settings['concurrent_downloads']}",
f"**Max Retries:** {settings['max_retries']}",
f"**Retry Delay:** {settings['retry_delay']}s",
]
),
inline=False,
)
async def _add_site_settings(
self,
embed: discord.Embed,
settings: Dict[str, Any]
self, embed: discord.Embed, settings: Dict[str, Any]
) -> None:
"""Add site settings to embed"""
enabled_sites = settings["enabled_sites"]
sites_text = ", ".join(enabled_sites) if enabled_sites else "All sites"
embed.add_field(
name="Enabled Sites",
value=sites_text,
inline=False
)
embed.add_field(name="Enabled Sites", value=sites_text, inline=False)
async def _get_channel_mentions(
self,
guild: discord.Guild,
settings: Dict[str, Any]
self, guild: discord.Guild, settings: Dict[str, Any]
) -> Dict[str, str]:
"""Get channel mentions with error handling"""
try:
@@ -173,7 +159,7 @@ class SettingsFormatter:
archive_channel = guild.get_channel(settings["archive_channel"])
notification_channel = guild.get_channel(settings["notification_channel"])
log_channel = guild.get_channel(settings["log_channel"])
# Get monitored channels
monitored_channels = []
for channel_id in settings["monitored_channels"]:
@@ -183,9 +169,17 @@ class SettingsFormatter:
return {
"archive": archive_channel.mention if archive_channel else "Not set",
"notification": notification_channel.mention if notification_channel else "Same as archive",
"notification": (
notification_channel.mention
if notification_channel
else "Same as archive"
),
"log": log_channel.mention if log_channel else "Not set",
"monitored": "\n".join(monitored_channels) if monitored_channels else "All channels"
"monitored": (
"\n".join(monitored_channels)
if monitored_channels
else "All channels"
),
}
except Exception as e:
@@ -194,14 +188,10 @@ class SettingsFormatter:
"archive": "Error",
"notification": "Error",
"log": "Error",
"monitored": "Error getting channels"
"monitored": "Error getting channels",
}
async def _get_role_names(
self,
guild: discord.Guild,
role_ids: List[int]
) -> str:
async def _get_role_names(self, guild: discord.Guild, role_ids: List[int]) -> str:
"""Get role names with error handling"""
try:
role_names = []
@@ -209,8 +199,10 @@ class SettingsFormatter:
role = guild.get_role(role_id)
if role:
role_names.append(role.name)
return ", ".join(role_names) if role_names else "All roles (no restrictions)"
return (
", ".join(role_names) if role_names else "All roles (no restrictions)"
)
except Exception as e:
logger.error(f"Error getting role names: {e}")

View File

@@ -3,12 +3,13 @@
import logging
from typing import Any, Dict, List, Union
try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
logger = logging.getLogger("ConfigValidation")
@@ -27,11 +28,11 @@ class ValidationManager:
def validate_setting(self, setting: str, value: Any) -> None:
"""Validate a setting value against constraints
Args:
setting: Name of the setting to validate
value: Value to validate
Raises:
ConfigError: If validation fails
"""
@@ -72,7 +73,9 @@ class ValidationManager:
def _validate_concurrent_downloads(self, value: int) -> None:
"""Validate concurrent downloads setting"""
if not isinstance(value, int) or not (1 <= value <= self.MAX_CONCURRENT_DOWNLOADS):
if not isinstance(value, int) or not (
1 <= value <= self.MAX_CONCURRENT_DOWNLOADS
):
raise ConfigError(
f"Concurrent downloads must be between 1 and {self.MAX_CONCURRENT_DOWNLOADS}"
)
@@ -87,9 +90,7 @@ class ValidationManager:
def _validate_max_retries(self, value: int) -> None:
"""Validate max retries setting"""
if not isinstance(value, int) or not (0 <= value <= self.MAX_RETRIES):
raise ConfigError(
f"Max retries must be between 0 and {self.MAX_RETRIES}"
)
raise ConfigError(f"Max retries must be between 0 and {self.MAX_RETRIES}")
def _validate_retry_delay(self, value: int) -> None:
"""Validate retry delay setting"""
@@ -124,17 +125,22 @@ class ValidationManager:
if setting.endswith("_channel") and value is not None:
if not isinstance(value, int):
raise ConfigError(f"{setting} must be a channel ID (int) or None")
elif setting in ["enabled", "delete_after_repost", "disable_update_check", "use_database"]:
elif setting in [
"enabled",
"delete_after_repost",
"disable_update_check",
"use_database",
]:
self._validate_boolean(value)
elif setting in ["monitored_channels", "allowed_roles", "enabled_sites"]:
self._validate_list(value)
def validate_all_settings(self, settings: Dict[str, Any]) -> None:
"""Validate all settings in a configuration dictionary
Args:
settings: Dictionary of settings to validate
Raises:
ConfigError: If any validation fails
"""