Files
SkrzynkaImpostora/bot/backend/database/DatabaseManager.js
2025-07-21 00:45:28 +02:00

235 lines
9.1 KiB
JavaScript

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 };