const { Pool } = require('pg'); require('dotenv').config(); class DatabaseManager { constructor() { this.pool = new Pool({ connectionString: process.env.DATABASE_URL, ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false }); } async initialize() { try { await this.createTables(); console.log('Tabele bazy danych utworzone pomyślnie'); } catch (error) { console.error('Błąd podczas inicjalizacji bazy danych:', error); throw error; } } async createTables() { const createTablesSQL = ` -- Tabela serwerów Discord CREATE TABLE IF NOT EXISTS guilds ( id VARCHAR(20) PRIMARY KEY, name VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Tabela kanałów powitalnych CREATE TABLE IF NOT EXISTS welcome_channels ( id SERIAL PRIMARY KEY, guild_id VARCHAR(20) REFERENCES guilds(id) ON DELETE CASCADE, channel_id VARCHAR(20) NOT NULL, channel_name VARCHAR(100), is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(guild_id) ); -- Tabela wiadomości powitalnych CREATE TABLE IF NOT EXISTS welcome_messages ( id SERIAL PRIMARY KEY, guild_id VARCHAR(20) REFERENCES guilds(id) ON DELETE CASCADE, content TEXT NOT NULL, embed_data JSONB, message_id VARCHAR(20), is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Tabela użytkowników panelu web CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, discord_id VARCHAR(20) UNIQUE NOT NULL, username VARCHAR(32) NOT NULL, discriminator VARCHAR(4), avatar VARCHAR(255), email VARCHAR(255), role VARCHAR(20) DEFAULT 'viewer', is_active BOOLEAN DEFAULT true, last_login TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Tabela historii wersji wiadomości CREATE TABLE IF NOT EXISTS message_revisions ( id SERIAL PRIMARY KEY, message_id INTEGER REFERENCES welcome_messages(id) ON DELETE CASCADE, content TEXT NOT NULL, embed_data JSONB, user_id INTEGER REFERENCES users(id), revision_number INTEGER NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Tabela uprawnień użytkowników do serwerów CREATE TABLE IF NOT EXISTS user_guild_permissions ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, guild_id VARCHAR(20) REFERENCES guilds(id) ON DELETE CASCADE, role VARCHAR(20) DEFAULT 'viewer', granted_by INTEGER REFERENCES users(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_id, guild_id) ); -- Indeksy dla wydajności CREATE INDEX IF NOT EXISTS idx_guilds_id ON guilds(id); CREATE INDEX IF NOT EXISTS idx_welcome_channels_guild_id ON welcome_channels(guild_id); CREATE INDEX IF NOT EXISTS idx_welcome_messages_guild_id ON welcome_messages(guild_id); CREATE INDEX IF NOT EXISTS idx_users_discord_id ON users(discord_id); CREATE INDEX IF NOT EXISTS idx_message_revisions_message_id ON message_revisions(message_id); CREATE INDEX IF NOT EXISTS idx_user_guild_permissions_user_guild ON user_guild_permissions(user_id, guild_id); `; await this.pool.query(createTablesSQL); } // Metody dla zarządzania serwerami async addGuild(guildId, guildName) { const query = ` INSERT INTO guilds (id, name) VALUES ($1, $2) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, updated_at = CURRENT_TIMESTAMP `; await this.pool.query(query, [guildId, guildName]); } async getGuild(guildId) { const query = 'SELECT * FROM guilds WHERE id = $1'; const result = await this.pool.query(query, [guildId]); return result.rows[0]; } // Metody dla kanałów powitalnych async setWelcomeChannel(guildId, channelId, channelName) { const query = ` INSERT INTO welcome_channels (guild_id, channel_id, channel_name) VALUES ($1, $2, $3) ON CONFLICT (guild_id) DO UPDATE SET channel_id = EXCLUDED.channel_id, channel_name = EXCLUDED.channel_name, is_active = true, updated_at = CURRENT_TIMESTAMP `; await this.pool.query(query, [guildId, channelId, channelName]); } async getWelcomeChannel(guildId) { const query = 'SELECT * FROM welcome_channels WHERE guild_id = $1 AND is_active = true'; const result = await this.pool.query(query, [guildId]); return result.rows[0]; } // Metody dla wiadomości powitalnych async saveWelcomeMessage(guildId, content, embedData = null, messageId = null) { const query = ` INSERT INTO welcome_messages (guild_id, content, embed_data, message_id) VALUES ($1, $2, $3, $4) RETURNING * `; const result = await this.pool.query(query, [guildId, content, embedData, messageId]); return result.rows[0]; } async updateWelcomeMessage(guildId, content, embedData = null, messageId = null) { const query = ` UPDATE welcome_messages SET content = $2, embed_data = $3, message_id = $4, updated_at = CURRENT_TIMESTAMP WHERE guild_id = $1 AND is_active = true RETURNING * `; const result = await this.pool.query(query, [guildId, content, embedData, messageId]); return result.rows[0]; } async getWelcomeMessage(guildId) { const query = 'SELECT * FROM welcome_messages WHERE guild_id = $1 AND is_active = true ORDER BY created_at DESC LIMIT 1'; const result = await this.pool.query(query, [guildId]); return result.rows[0]; } // Metody dla użytkowników async saveUser(discordUser) { const query = ` INSERT INTO users (discord_id, username, discriminator, avatar, email) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (discord_id) DO UPDATE SET username = EXCLUDED.username, discriminator = EXCLUDED.discriminator, avatar = EXCLUDED.avatar, email = EXCLUDED.email, last_login = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP RETURNING * `; const result = await this.pool.query(query, [ discordUser.id, discordUser.username, discordUser.discriminator || '0000', discordUser.avatar, discordUser.email ]); return result.rows[0]; } async getUser(discordId) { const query = 'SELECT * FROM users WHERE discord_id = $1'; const result = await this.pool.query(query, [discordId]); return result.rows[0]; } // Metody dla historii wersji async saveMessageRevision(messageId, content, embedData, userId) { // Pobierz aktualny numer rewizji const revisionQuery = 'SELECT COALESCE(MAX(revision_number), 0) + 1 as next_revision FROM message_revisions WHERE message_id = $1'; const revisionResult = await this.pool.query(revisionQuery, [messageId]); const nextRevision = revisionResult.rows[0].next_revision; const query = ` INSERT INTO message_revisions (message_id, content, embed_data, user_id, revision_number) VALUES ($1, $2, $3, $4, $5) RETURNING * `; const result = await this.pool.query(query, [messageId, content, embedData, userId, nextRevision]); return result.rows[0]; } async getMessageRevisions(messageId) { const query = ` SELECT mr.*, u.username FROM message_revisions mr LEFT JOIN users u ON mr.user_id = u.id WHERE mr.message_id = $1 ORDER BY mr.revision_number DESC `; const result = await this.pool.query(query, [messageId]); return result.rows; } async close() { await this.pool.end(); } } module.exports = { DatabaseManager };