* health check * Update Dockerfile * simplifying the deployment * Update Bot.js makes the find team command public * test (#9) * Dev (#7) * health check * Update Dockerfile * simplifying the deployment * Dev (#8) * health check * Update Dockerfile * simplifying the deployment * Update Bot.js makes the find team command public * Update PlayerService.js * massive update???? could break stuff * Update Bot.js update
385 lines
12 KiB
JavaScript
385 lines
12 KiB
JavaScript
const { createClient } = require('@supabase/supabase-js');
|
|
const Logger = require('../utils/Logger');
|
|
|
|
class SupabaseService {
|
|
constructor() {
|
|
this.logger = new Logger('SupabaseService');
|
|
const supabaseUrl = process.env.SUPABASE_URL;
|
|
const supabaseKey = process.env.SUPABASE_KEY;
|
|
|
|
if (!supabaseUrl || !supabaseKey) {
|
|
this.logger.error('Missing configuration', {
|
|
hasUrl: !!supabaseUrl,
|
|
hasKey: !!supabaseKey
|
|
});
|
|
this.supabase = null;
|
|
} else {
|
|
this.supabase = createClient(supabaseUrl, supabaseKey, {
|
|
auth: {
|
|
autoRefreshToken: false,
|
|
persistSession: false
|
|
},
|
|
global: {
|
|
headers: {
|
|
'apikey': supabaseKey
|
|
}
|
|
}
|
|
});
|
|
this.logger.debug('Supabase client created');
|
|
}
|
|
}
|
|
|
|
async testConnection() {
|
|
if (!this.supabase) {
|
|
this.logger.error('Client not initialized');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
this.logger.debug('Testing database connection...');
|
|
|
|
// Test servers table
|
|
const { data: serverTest, error: serverError } = await this.supabase
|
|
.from('servers')
|
|
.select('count')
|
|
.limit(1);
|
|
|
|
if (serverError) {
|
|
this.logger.error('Server table test failed:', serverError);
|
|
return false;
|
|
}
|
|
|
|
// Test games table
|
|
const { data: gameTest, error: gameError } = await this.supabase
|
|
.from('games')
|
|
.select('count')
|
|
.limit(1);
|
|
|
|
if (gameError) {
|
|
this.logger.error('Games table test failed:', gameError);
|
|
return false;
|
|
}
|
|
|
|
this.logger.info('Database connection successful');
|
|
return true;
|
|
} catch (error) {
|
|
this.logger.error('Connection test failed:', {
|
|
error: error.message,
|
|
stack: error.stack
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async ensureServerRegistered(guildId, serverName) {
|
|
try {
|
|
this.logger.debug('Ensuring server is registered', { guildId, serverName });
|
|
|
|
// Try to find existing server
|
|
const { data: existingServer, error: fetchError } = await this.supabase
|
|
.from('servers')
|
|
.select('*')
|
|
.eq('discord_server_id', guildId)
|
|
.single();
|
|
|
|
// If server exists, return it
|
|
if (existingServer) {
|
|
this.logger.debug('Server already registered', {
|
|
serverId: existingServer.id,
|
|
guildId,
|
|
serverName: existingServer.server_name
|
|
});
|
|
return existingServer;
|
|
}
|
|
|
|
// If server doesn't exist, create it
|
|
this.logger.debug('Registering new server', { guildId, serverName });
|
|
const { data: newServer, error: insertError } = await this.supabase
|
|
.from('servers')
|
|
.insert([{
|
|
discord_server_id: guildId,
|
|
server_name: serverName,
|
|
active: true
|
|
}])
|
|
.select()
|
|
.single();
|
|
|
|
if (insertError) {
|
|
this.logger.error('Failed to register server', {
|
|
error: insertError,
|
|
guildId,
|
|
serverName
|
|
});
|
|
throw insertError;
|
|
}
|
|
|
|
this.logger.info('New server registered successfully', {
|
|
serverId: newServer.id,
|
|
guildId,
|
|
serverName
|
|
});
|
|
|
|
return newServer;
|
|
} catch (error) {
|
|
this.logger.error('Error in ensureServerRegistered:', {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
guildId,
|
|
serverName
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Update the addSubscription method to use ensureServerRegistered
|
|
async addSubscription(guildId, gameName, channelId, serverName) {
|
|
if (!this.supabase) {
|
|
this.logger.error('Client not initialized');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
this.logger.debug('Adding subscription', { guildId, gameName, channelId });
|
|
|
|
// Ensure server is registered
|
|
const server = await this.ensureServerRegistered(guildId, serverName);
|
|
if (!server) {
|
|
throw new Error('Failed to ensure server registration');
|
|
}
|
|
|
|
// Get game ID
|
|
const { data: gameData, error: gameError } = await this.supabase
|
|
.from('games')
|
|
.select('id')
|
|
.eq('name', gameName)
|
|
.eq('active', true)
|
|
.single();
|
|
|
|
if (gameError) {
|
|
this.logger.error('Game fetch error:', { gameError, gameName });
|
|
throw gameError;
|
|
}
|
|
|
|
// Create subscription
|
|
const { data, error } = await this.supabase
|
|
.from('server_game_preferences')
|
|
.upsert({
|
|
server_id: server.id,
|
|
game_id: gameData.id,
|
|
notification_channel_id: channelId
|
|
}, {
|
|
onConflict: '(server_id,game_id)',
|
|
returning: true
|
|
});
|
|
|
|
if (error) {
|
|
this.logger.error('Subscription upsert error:', { error });
|
|
throw error;
|
|
}
|
|
|
|
this.logger.debug('Subscription added successfully', {
|
|
serverId: server.id,
|
|
gameId: gameData.id,
|
|
channelId
|
|
});
|
|
|
|
return data;
|
|
} catch (error) {
|
|
this.logger.error('Error in addSubscription:', {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
guildId,
|
|
gameName
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getSubscriptions(guildId) {
|
|
if (!this.supabase) {
|
|
this.logger.error('Client not initialized');
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
this.logger.debug('Fetching subscriptions', { guildId });
|
|
|
|
const { data, error } = await this.supabase
|
|
.from('server_game_preferences')
|
|
.select(`
|
|
games (name),
|
|
notification_channel_id,
|
|
servers!inner (discord_server_id)
|
|
`)
|
|
.eq('servers.discord_server_id', guildId);
|
|
|
|
if (error) {
|
|
this.logger.error('Error fetching subscriptions:', { error, guildId });
|
|
throw error;
|
|
}
|
|
|
|
this.logger.debug('Subscriptions fetched', {
|
|
count: data?.length || 0,
|
|
guildId
|
|
});
|
|
|
|
return data || [];
|
|
} catch (error) {
|
|
this.logger.error('Error in getSubscriptions:', {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
guildId
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async addSubscription(guildId, gameName, channelId) {
|
|
if (!this.supabase) {
|
|
this.logger.error('Client not initialized');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
this.logger.debug('Adding subscription', { guildId, gameName, channelId });
|
|
|
|
// First, get or create server record
|
|
const { data: serverData, error: serverError } = await this.supabase
|
|
.from('servers')
|
|
.upsert({
|
|
discord_server_id: guildId,
|
|
active: true
|
|
}, {
|
|
onConflict: 'discord_server_id',
|
|
returning: true
|
|
});
|
|
|
|
if (serverError) {
|
|
this.logger.error('Server upsert error:', { serverError, guildId });
|
|
throw serverError;
|
|
}
|
|
|
|
if (!serverData || serverData.length === 0) {
|
|
this.logger.error('Server creation failed - no data returned', { guildId });
|
|
throw new Error('Server creation failed');
|
|
}
|
|
|
|
// Get game ID
|
|
const { data: gameData, error: gameError } = await this.supabase
|
|
.from('games')
|
|
.select('id')
|
|
.eq('name', gameName)
|
|
.eq('active', true)
|
|
.single();
|
|
|
|
if (gameError) {
|
|
this.logger.error('Game fetch error:', { gameError, gameName });
|
|
throw gameError;
|
|
}
|
|
|
|
// Create subscription
|
|
const { data, error } = await this.supabase
|
|
.from('server_game_preferences')
|
|
.upsert({
|
|
server_id: serverData[0].id,
|
|
game_id: gameData.id,
|
|
notification_channel_id: channelId
|
|
}, {
|
|
onConflict: '(server_id,game_id)',
|
|
returning: true
|
|
});
|
|
|
|
if (error) {
|
|
this.logger.error('Subscription upsert error:', { error });
|
|
throw error;
|
|
}
|
|
|
|
this.logger.debug('Subscription added successfully', {
|
|
serverId: serverData[0].id,
|
|
gameId: gameData.id,
|
|
channelId
|
|
});
|
|
|
|
return data;
|
|
} catch (error) {
|
|
this.logger.error('Error in addSubscription:', {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
guildId,
|
|
gameName
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async removeSubscription(guildId, gameName) {
|
|
if (!this.supabase) {
|
|
this.logger.error('Client not initialized');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
this.logger.debug('Removing subscription', { guildId, gameName });
|
|
|
|
// Get server ID
|
|
const { data: serverData, error: serverError } = await this.supabase
|
|
.from('servers')
|
|
.select('id')
|
|
.eq('discord_server_id', guildId)
|
|
.single();
|
|
|
|
if (serverError) {
|
|
this.logger.error('Server fetch error:', { serverError, guildId });
|
|
throw serverError;
|
|
}
|
|
|
|
// Get game ID
|
|
const { data: gameData, error: gameError } = await this.supabase
|
|
.from('games')
|
|
.select('id')
|
|
.eq('name', gameName)
|
|
.single();
|
|
|
|
if (gameError) {
|
|
this.logger.error('Game fetch error:', { gameError, gameName });
|
|
throw gameError;
|
|
}
|
|
|
|
// Delete subscription
|
|
const { data, error } = await this.supabase
|
|
.from('server_game_preferences')
|
|
.delete()
|
|
.match({
|
|
server_id: serverData.id,
|
|
game_id: gameData.id
|
|
})
|
|
.single();
|
|
|
|
if (error) {
|
|
this.logger.error('Subscription deletion error:', { error });
|
|
throw error;
|
|
}
|
|
|
|
this.logger.debug('Subscription removed successfully', {
|
|
serverId: serverData.id,
|
|
gameId: gameData.id
|
|
});
|
|
|
|
return data;
|
|
} catch (error) {
|
|
this.logger.error('Error in removeSubscription:', {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
guildId,
|
|
gameName
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
getClient() {
|
|
return this.supabase;
|
|
}
|
|
}
|
|
|
|
module.exports = SupabaseService; |