This commit is contained in:
Slipstream 2025-05-03 18:10:42 -06:00
parent 34f94ca462
commit 16ae8e0841
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
4 changed files with 187 additions and 15 deletions

View File

@ -45,7 +45,7 @@ class ApiSettings(BaseSettings):
DISCORD_CLIENT_ID: str
DISCORD_CLIENT_SECRET: str
DISCORD_REDIRECT_URI: str
DISCORD_BOT_TOKEN: str # Add bot token for API calls
DISCORD_BOT_TOKEN: Optional[str] = None # Add bot token for API calls (optional)
# Secret key for dashboard session management
DASHBOARD_SECRET_KEY: str = "a_default_secret_key_for_development_only" # Provide a default for dev
@ -928,7 +928,14 @@ async def dashboard_get_guild_channels(
log.info(f"Dashboard: Fetching channels for guild {guild_id} requested by user {current_user['user_id']}")
try:
# Use Discord Bot Token to fetch channels
# Use Discord Bot Token to fetch channels if available
if not settings.DISCORD_BOT_TOKEN:
log.error("Dashboard: DISCORD_BOT_TOKEN not set in environment variables")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Bot token not configured. Please set DISCORD_BOT_TOKEN in environment variables."
)
bot_headers = {'Authorization': f'Bot {settings.DISCORD_BOT_TOKEN}'}
# Add rate limit handling
@ -978,12 +985,19 @@ async def dashboard_get_guild_channels(
}
# If we're getting close to the rate limit, log a warning
if rate_limit['remaining'] and int(rate_limit['remaining']) < 5:
log.warning(
f"Dashboard: Rate limit warning: {rate_limit['remaining']}/{rate_limit['limit']} "
f"requests remaining in bucket {rate_limit['bucket']}. "
f"Resets in {rate_limit['reset_after']}s"
)
if rate_limit['remaining'] and rate_limit['limit']:
try:
remaining = int(rate_limit['remaining'])
limit = int(rate_limit['limit'])
if remaining < 5:
log.warning(
f"Dashboard: Rate limit warning: {remaining}/{limit} "
f"requests remaining in bucket {rate_limit['bucket'] or 'unknown'}. "
f"Resets in {rate_limit['reset_after'] or 'unknown'}s"
)
except (ValueError, TypeError):
# Handle case where headers might be present but not valid integers
pass
resp.raise_for_status()
channels = await resp.json()
@ -1025,7 +1039,14 @@ async def dashboard_get_guild_roles(
log.info(f"Dashboard: Fetching roles for guild {guild_id} requested by user {current_user['user_id']}")
try:
# Use Discord Bot Token to fetch roles
# Use Discord Bot Token to fetch roles if available
if not settings.DISCORD_BOT_TOKEN:
log.error("Dashboard: DISCORD_BOT_TOKEN not set in environment variables")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Bot token not configured. Please set DISCORD_BOT_TOKEN in environment variables."
)
bot_headers = {'Authorization': f'Bot {settings.DISCORD_BOT_TOKEN}'}
# Add rate limit handling
@ -1113,7 +1134,14 @@ async def dashboard_get_guild_commands(
log.info(f"Dashboard: Fetching commands for guild {guild_id} requested by user {current_user['user_id']}")
try:
# Use Discord Bot Token to fetch application commands
# Use Discord Bot Token to fetch application commands if available
if not settings.DISCORD_BOT_TOKEN:
log.error("Dashboard: DISCORD_BOT_TOKEN not set in environment variables")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Bot token not configured. Please set DISCORD_BOT_TOKEN in environment variables."
)
bot_headers = {'Authorization': f'Bot {settings.DISCORD_BOT_TOKEN}'}
application_id = settings.DISCORD_CLIENT_ID # This should be the same as your bot's application ID

View File

@ -506,3 +506,24 @@
visibility: visible;
opacity: 1;
}
/* Error message */
.error-message {
background-color: rgba(220, 53, 69, 0.1);
border-left: 4px solid var(--danger-color);
border-radius: var(--radius-md);
padding: var(--spacing-3) var(--spacing-4);
margin: var(--spacing-3) 0;
color: var(--text-primary);
}
.error-message p {
margin: var(--spacing-1) 0;
}
.error-message code {
background-color: rgba(0, 0, 0, 0.1);
padding: 2px 4px;
border-radius: 3px;
font-family: monospace;
}

View File

@ -342,6 +342,39 @@ function loadDashboardData() {
loadGlobalSettings();
}
/**
* Show a global error message about missing bot token
*/
function showBotTokenMissingError() {
// Create error banner
const errorBanner = document.createElement('div');
errorBanner.className = 'error-message';
errorBanner.style.margin = '0';
errorBanner.style.borderRadius = '0';
errorBanner.style.position = 'sticky';
errorBanner.style.top = '0';
errorBanner.style.zIndex = '1000';
errorBanner.innerHTML = `
<div style="display: flex; align-items: center; justify-content: space-between;">
<div>
<strong>Configuration Error:</strong> Discord Bot Token is not configured.
<p>Some features like channel selection, role management, and command permissions will not work.</p>
<p>Please set the <code>DISCORD_BOT_TOKEN</code> environment variable in your .env file.</p>
</div>
<button class="btn btn-sm" id="close-error-banner" style="background: transparent; border: none;">×</button>
</div>
`;
// Add to the top of the page
document.body.insertBefore(errorBanner, document.body.firstChild);
// Add close button functionality
document.getElementById('close-error-banner').addEventListener('click', () => {
errorBanner.remove();
});
}
/**
* Load guilds for server select dropdown
*/
@ -556,7 +589,37 @@ function loadGuildChannels(guildId) {
})
.catch(error => {
console.error('Error loading channels:', error);
Toast.error('Failed to load channels. Please try again.');
// Check for specific error about missing bot token
if (error.status === 503 && error.message && error.message.includes('Bot token not configured')) {
// Show global error banner
showBotTokenMissingError();
// Show a more helpful message in the channel selects
if (welcomeChannelSelect) {
welcomeChannelSelect.innerHTML = '<option value="">Bot token not configured</option>';
welcomeChannelSelect.disabled = true;
}
if (goodbyeChannelSelect) {
goodbyeChannelSelect.innerHTML = '<option value="">Bot token not configured</option>';
goodbyeChannelSelect.disabled = true;
}
// Add a visible error message
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.innerHTML = `
<p>The Discord bot token is not configured. Channel selection is unavailable.</p>
<p>Please set the <code>DISCORD_BOT_TOKEN</code> environment variable in your .env file.</p>
`;
// Add the error message near the channel selects
if (welcomeChannelSelect && welcomeChannelSelect.parentNode) {
welcomeChannelSelect.parentNode.appendChild(errorDiv);
}
} else {
Toast.error('Failed to load channels. Please try again.');
}
});
}
@ -588,7 +651,31 @@ function loadGuildRoles(guildId) {
})
.catch(error => {
console.error('Error loading roles:', error);
Toast.error('Failed to load roles. Please try again.');
// Check for specific error about missing bot token
if (error.status === 503 && error.message && error.message.includes('Bot token not configured')) {
// Show global error banner (if not already shown)
showBotTokenMissingError();
// Show a more helpful message in the role select
roleSelect.innerHTML = '<option value="">Bot token not configured</option>';
roleSelect.disabled = true;
// Add a visible error message
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.innerHTML = `
<p>The Discord bot token is not configured. Role selection is unavailable.</p>
<p>Please set the <code>DISCORD_BOT_TOKEN</code> environment variable in your .env file.</p>
`;
// Add the error message near the role select
if (roleSelect.parentNode) {
roleSelect.parentNode.appendChild(errorDiv);
}
} else {
Toast.error('Failed to load roles. Please try again.');
}
});
}
@ -623,7 +710,31 @@ function loadGuildCommands(guildId) {
})
.catch(error => {
console.error('Error loading commands:', error);
Toast.error('Failed to load commands. Please try again.');
// Check for specific error about missing bot token
if (error.status === 503 && error.message && error.message.includes('Bot token not configured')) {
// Show global error banner (if not already shown)
showBotTokenMissingError();
// Show a more helpful message in the command select
commandSelect.innerHTML = '<option value="">Bot token not configured</option>';
commandSelect.disabled = true;
// Add a visible error message
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.innerHTML = `
<p>The Discord bot token is not configured. Command selection is unavailable.</p>
<p>Please set the <code>DISCORD_BOT_TOKEN</code> environment variable in your .env file.</p>
`;
// Add the error message near the command select
if (commandSelect.parentNode) {
commandSelect.parentNode.appendChild(errorDiv);
}
} else {
Toast.error('Failed to load commands. Please try again.');
}
});
}

View File

@ -185,8 +185,20 @@ const API = {
};
// If we're getting close to the rate limit, log a warning
if (rateLimit.remaining && parseInt(rateLimit.remaining) < 5) {
console.warn(`API Rate limit warning: ${rateLimit.remaining}/${rateLimit.limit} requests remaining in bucket ${rateLimit.bucket}. Resets in ${rateLimit.resetAfter}s`);
if (rateLimit.remaining && rateLimit.limit) {
try {
const remaining = parseInt(rateLimit.remaining);
const limit = parseInt(rateLimit.limit);
if (remaining < 5) {
console.warn(
`API Rate limit warning: ${remaining}/${limit} requests remaining` +
(rateLimit.bucket ? ` in bucket ${rateLimit.bucket}` : '') +
(rateLimit.resetAfter ? `. Resets in ${rateLimit.resetAfter}s` : '')
);
}
} catch (e) {
// Ignore parsing errors for rate limit headers
}
}
// Handle rate limiting with automatic retry