Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions app/src/auto_validator/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@


def uploaded_file_size_validator(value):
if value.size > config.API_UPLOAD_MAX_SIZE:
raise serializers.ValidationError(f"File size must be < {config.API_UPLOAD_MAX_SIZE}B")
max_size = config.API_UPLOAD_MAX_SIZE
# Handle if Constance returns a dict or JSON string
if isinstance(max_size, str):
import json
try:
max_size_data = json.loads(max_size)
max_size = int(max_size_data.get('__value__', max_size_data))
except (json.JSONDecodeError, ValueError):
max_size = int(max_size)
max_size = int(max_size)
if value.size > max_size:
raise serializers.ValidationError(f"File size must be < {max_size}B")


class UploadedFileSerializer(serializers.ModelSerializer):
Expand Down
29 changes: 24 additions & 5 deletions app/src/auto_validator/discord_bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,26 @@ async def start_bot(self) -> None:
await self.start(self.config["DISCORD_BOT_TOKEN"])

async def setup_hook(self) -> None:
asyncio.create_task(self.listen_to_redis())
self.logger.info("Setup hook called, starting Redis listener task")
task = asyncio.create_task(self.listen_to_redis())

# Add error callback to catch any exceptions
def task_error_callback(t):
try:
t.result()
except Exception as e:
self.logger.error(f"Redis listener task failed: {e}", exc_info=True)

task.add_done_callback(task_error_callback)

async def listen_to_redis(self):
pubsub = self.redis_client.pubsub()
pubsub.subscribe("bot_commands")
self.logger.info("Redis listener started and subscribed to bot_commands channel")
while True:
message = pubsub.get_message()
message = await asyncio.to_thread(pubsub.get_message)
if message and message["type"] == "message":
self.logger.info(f"Received Redis message: {message}")
data = json.loads(message["data"])
await self.handle_command(data)
await asyncio.sleep(0.1)
Expand All @@ -81,11 +93,13 @@ async def on_ready(self) -> None:
"""
Called when the bot is connected and ready. Logs connection details.
"""

self.logger.info(f"Bot connected as {self.user}")
for guild in self.guilds:
self.logger.info(f"Connected to guild: {guild.name}")
await self.config_manager.update_config_and_synchronize.start()
try:
await self.config_manager.update_config_and_synchronize.start()
except Exception as e:
self.logger.error(f"Failed to start config sync: {e}", exc_info=True)

async def on_member_join(self, member: discord.Member) -> None:
"""
Expand Down Expand Up @@ -192,6 +206,11 @@ async def _send_invite_link(self, user_id: UserID, channel_name: ChannelName) ->
self.logger.info(f"Sent invite to {user.name}.")
except discord.NotFound:
self.logger.error(f"User with ID {user_id} not found.")
except discord.Forbidden:
self.logger.warning(
f"Cannot send DM to user {user_id}. User may have DMs disabled or blocked the bot. "
f"Invite link created but not sent: {invite.url}"
)
except discord.HTTPException as e:
self.logger.error(f"Failed to send invite: {e}")

Expand Down Expand Up @@ -276,7 +295,7 @@ async def _revoke_channel_permissions(self, user_id: UserID, channel_name: Chann
# Revoke the permissions of the user for the specified channel
await channel.set_permissions(member, overwrite=overwrite)
self.logger.info(f"Revoked read/write permissions of {member.name} for channel '{channel_name}'.")
await member.send(f"Yor access to the '{channel_name}' channel has been revoked.")
await member.send(f"Your access to the '{channel_name}' channel has been revoked.")

def _is_bot_channel(self, channel_name: ChannelName) -> bool:
bot_channel_regex = r"^[td]?\d{3}-[\S]+$"
Expand Down
11 changes: 10 additions & 1 deletion app/src/auto_validator/discord_bot/subnet_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,16 @@ async def synchronize_discord_with_subnet_config(self) -> None:

def get_current_channel_user_mapping(self, guild: discord.Guild) -> dict[ChannelName, list[UserID]]:
channels_to_users = {}
for channel in guild.text_channels:
# Get the category we're managing
normalized_category_name = self.config["CATEGORY_NAME"].strip().lower()
category = discord.utils.find(lambda c: c.name.strip().lower() == normalized_category_name, guild.categories)

# If category doesn't exist, return empty mapping (no current channels)
if category is None:
return channels_to_users

# Only look at channels in our managed category
for channel in category.text_channels:
if self.bot._is_bot_channel(channel.name):
users_in_channel = [
UserID(member.id) for member in channel.members if channel.permissions_for(member).view_channel
Expand Down
3 changes: 2 additions & 1 deletion app/src/auto_validator/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ def configure_structlog():

DISCORD_BOT_TOKEN = env("DISCORD_BOT_TOKEN", default="")
GUILD_ID = env("GUILD_ID", default="")
SUBNET_CONFIG_URL = env("SUBNET_CONFIG_URL", default="")
BOT_NAME = env("BOT_NAME", default="")
CATEGORY_NAME = env("CATEGORY_NAME", default="")

Expand All @@ -443,7 +444,7 @@ def configure_structlog():

LOCAL_SUBNETS_SCRIPTS_PATH = pathlib.Path(
env("LOCAL_SUBNETS_SCRIPTS_PATH", default="~/.config/auto-validator/subnet-scripts")
)
).expanduser()

LOCAL_VALIDATORS_CONFIG_PATH = pathlib.Path(
env("LOCAL_VALIDATORS_CONFIG_PATH", default="~/.config/auto-validator/validators.yaml")
Expand Down
Loading
Loading