Files
BattleBot/src/services/PlayerService.js
VinceC dd8aa456d9 v1.2.11: Add tournaments command with filtering and improve error handling
Features:
- Add /tournaments command with status and game filters
- Add tournament API integration to PlayerService
- Add beautiful tournament embed builders with prize pools
- Protect sync-games from overwriting manual customizations
- Improve error handling with proper MessageFlags

Changes:
- Add getTournamentsData() and getTournamentData() to PlayerService
- Add tournament command handler with pagination support
- Add tournament embed builders with rich formatting
- Update deployment docs for v1.2.10 features
- Add issue tracker documentation
- Add tournament testing script
- Fix ephemeral flags throughout CommandHandler
- Improve permission checks with PermissionFlagsBits

Version: 1.2.11
2025-10-02 06:24:54 -05:00

171 lines
5.0 KiB
JavaScript

// src/services/PlayerService.js
const axios = require('axios');
class PlayerService {
constructor() {
this.baseUrl = 'https://www.vrbattles.gg';
}
async findUserByUsername(username) {
try {
console.log(`Fetching data for username: ${username}`);
const url = `${this.baseUrl}/api/get_player_data_by_username/${encodeURIComponent(username)}`;
console.log(`API URL: ${url}`);
const response = await axios.get(url, {
timeout: 5000
});
console.log('API Response:', JSON.stringify(response.data, null, 2));
if (response.data && response.data.success) {
// Parse player_data if it's a string
if (typeof response.data.player_data === 'string') {
try {
response.data.player_data = JSON.parse(response.data.player_data);
} catch (parseError) {
console.error('Error parsing player_data:', parseError);
}
}
}
return response.data;
} catch (error) {
console.error('Error fetching user data:', {
message: error.message,
response: error.response?.data,
status: error.response?.status
});
return null;
}
}
getBadgeImageUrl(badgeName) {
if (!badgeName) {
return `${this.baseUrl}/assets/images/badges/xp_badges/A/BADGE_A1_72p.png`;
}
badgeName = badgeName.toUpperCase().replace(/ /g, '_');
let badgeUrl = `${this.baseUrl}/assets/images/badges/xp_badges/`;
if (badgeName.startsWith('A')) {
badgeUrl += 'A/';
} else if (badgeName.startsWith('B')) {
badgeUrl += 'B/';
} else if (badgeName.startsWith('C')) {
badgeUrl += 'C/';
} else if (badgeName.startsWith('D')) {
badgeUrl += 'D/';
} else if (badgeName.startsWith('E')) {
badgeUrl += 'E/';
} else if (badgeName.startsWith('F')) {
badgeUrl += 'F/';
} else {
badgeUrl += 'A/'; // Default to A tier
}
badgeUrl += `BADGE_${badgeName}_72p.png`;
return badgeUrl;
}
getProfileUrl(username) {
return `${this.baseUrl}/profile/${username}`;
}
getStatsUrl(username) {
return `${this.baseUrl}/profile/${username}/stats`;
}
async getTournamentsData() {
try {
console.log('Fetching tournaments data...');
const url = `${this.baseUrl}/api/fetch/tournaments`;
console.log(`API URL: ${url}`);
const response = await axios.get(url, {
timeout: 5000,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
validateStatus: function (status) {
return status >= 200 && status < 300;
}
});
console.log('Tournaments API Response:', JSON.stringify(response.data, null, 2));
return response.data;
} catch (error) {
console.error('Error fetching tournaments data:', {
message: error.message,
response: error.response?.data,
status: error.response?.status
});
return { success: false, error: 'Failed to fetch tournaments data' };
}
}
async getTournamentData(tournamentId) {
const url = `${this.baseUrl}/api/get_tournament_data/${tournamentId}`;
const response = await axios.get(url);
return response.data;
}
async findTeamByName(teamName, gameFilter) {
try {
// Double-check sanitization here as well for defense in depth
if (!teamName || typeof teamName !== 'string') {
throw new Error('Invalid team name provided');
}
// Additional sanitization at the service level
const sanitizedTeamName = teamName
.replace(/[^a-zA-Z0-9\s\-_.]/g, '')
.trim()
.slice(0, 100);
if (!sanitizedTeamName) {
throw new Error('Invalid team name after sanitization');
}
// Use URL encoding for the query parameters
const encodedTeamName = encodeURIComponent(sanitizedTeamName);
const url = `${this.baseUrl}/api/get_team_data_by_name/${encodedTeamName}`;
const response = await axios.get(url, {
timeout: 5000, // 5 second timeout
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
validateStatus: function (status) {
return status >= 200 && status < 300; // Only accept success status codes
}
});
// Validate response structure
if (!response.data || typeof response.data !== 'object') {
throw new Error('Invalid response format from API');
}
// If game filter is provided, filter the teams
if (gameFilter && response.data.teams) {
response.data.teams = response.data.teams.filter(
team => team.game_name === gameFilter
);
}
return response.data;
} catch (error) {
this.logger.error('Error in findTeamByName:', {
error: error.message,
teamName,
gameFilter,
timestamp: new Date().toISOString()
});
return { success: false, error: 'Failed to fetch team data' };
}
}
}
module.exports = PlayerService;