diff --git a/.env.example b/.env.example index 47cbc76..ff8eb6e 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,10 @@ BOT_TOKEN='TOKEN_HERE' BOT_PREFIX=! BOT_ACTIVITY='Palworld' -BOT_LANGUAGE='en' \ No newline at end of file +BOT_LANGUAGE='en' + +#change with the data of your PostgreSql Database +BOT_POSTGRESQL_STRING_CONNECTION='postgresql://username:password@localhost:port' + +# Use this way if you do not intend to use a database +BOT_POSTGRESQL_STRING_CONNECTION='' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 54d204b..ee941e9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.db *.log +/.vs/* /dev/* /venv/* !gamedata/*.json diff --git a/cogs/economy/shop.py b/cogs/economy/shop.py index f1cdee3..afdee92 100644 --- a/cogs/economy/shop.py +++ b/cogs/economy/shop.py @@ -10,7 +10,7 @@ server_autocomplete, ) from utils.rconutility import RconUtility -from utils.kitutility import load_shop_items +from utils.kitutility import init_kitdb,load_shop_items import asyncio import utils.constants as constants import json @@ -18,8 +18,8 @@ from utils.errorhandling import restrict_command import logging -class ShopView(View): - def __init__(self, shop_items, currency, cog, selected_server): +class ShopView(View): + def __init__(self, shop_items, currency, cog, selected_server): super().__init__(timeout=None) self.shop_items = shop_items self.currency = currency @@ -95,7 +95,8 @@ async def next_button_callback(self, interaction: nextcord.Interaction): class ShopCog(commands.Cog): def __init__(self, bot): self.bot = bot - self.bot.loop.create_task(self.load_config()) + self.bot.loop.create_task(init_kitdb()) + self.bot.loop.create_task(self.load_config()) self.bot.loop.create_task(self.load_economy()) self.bot.loop.create_task(self.reload_cache()) self.rcon_util = RconUtility() diff --git a/requirements.txt b/requirements.txt index e9f1c6f..3ef255e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ gamercon-async==1.0.6 aiohttp==3.10.10 aiosqlite==0.20.0 pytz==2024.2 -steam==1.4.4 \ No newline at end of file +steam==1.4.4 +psycopg2-binary==2.9.6 \ No newline at end of file diff --git a/utils/database.py b/utils/database.py index ca666f7..6cbdc69 100644 --- a/utils/database.py +++ b/utils/database.py @@ -3,266 +3,749 @@ import aiosqlite import os +import psycopg2 +from urllib.parse import urlparse +from psycopg2 import sql +import utils.settings as settings DATABASE_PATH = os.path.join('data', 'palbot.db') +CONFIG_PG = '' + async def init_db(): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - CREATE TABLE IF NOT EXISTS servers ( - guild_id TEXT NOT NULL, - server_name TEXT PRIMARY KEY, - server_host TEXT NOT NULL, - rcon_port INTEGER NOT NULL, - connection_port INTEGER NOT NULL, - admin_pass TEXT NOT NULL - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS user_points ( - user_id TEXT PRIMARY KEY, - user_name TEXT NOT NULL, - points INTEGER NOT NULL DEFAULT 0, - steam_id TEXT, - verification_code TEXT - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS user_invites ( - user_id TEXT PRIMARY KEY, - user_name TEXT NOT NULL, - invite_count INTEGER NOT NULL DEFAULT 0 - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS economy_settings ( - setting_key TEXT PRIMARY KEY, - setting_value TEXT NOT NULL - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS server_events ( - server_name TEXT PRIMARY KEY, - channel_id INTEGER NOT NULL - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS server_queries ( - server_name TEXT PRIMARY KEY, - channel_id INTEGER NOT NULL, - status_message_id INTEGER, - players_message_id INTEGER - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS players ( - steamid TEXT PRIMARY KEY, - name TEXT NOT NULL, - playeruid TEXT NOT NULL - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS cooldowns ( - user_id TEXT NOT NULL, - command TEXT NOT NULL, - expires_at TIMESTAMP NOT NULL, - PRIMARY KEY (user_id, command) - ) - ''') - # Palgame tables - await db.execute(''' - CREATE TABLE IF NOT EXISTS user_pals ( - user_id TEXT NOT NULL, - pal_name TEXT NOT NULL, - experience INTEGER DEFAULT 0, - level INTEGER DEFAULT 1, - PRIMARY KEY (user_id, pal_name) - ) - ''') - # Settings for the economy system - default_settings = { - "currency_name": "Points", - "invite_reward": "10", - "work_reward_min": "20", - "work_reward_max": "50", - "work_timer": "360", - "daily_reward": "200", - "daily_timer": "86400", - "work_description": '["Your Pals butchered the invaders and earned {earned_points} {currency}!", "Anubis stumbled upon {earned_points} {currency} in the hot tub!"]', - "role_bonuses": '{"Server Booster": 10, "Supporter": 5}', - "vote_slug": "", - "vote_apikey": "", - "vote_reward": "100" + #Check if the connection string is available + if settings.connection_string: + def parse_connection_url(url): + result = urlparse(url) + return { + 'user': result.username, + 'password': result.password, + 'host': result.hostname, + 'port': result.port or 5432, # PostgreSQL default port is 5432 + } + + #Parse the connection string + conn_params = parse_connection_url(settings.connection_string) + + #Configure connection parameters + config = { + 'user': conn_params.get('user'), + 'password': conn_params.get('password'), + 'host': conn_params.get('host'), + 'port': conn_params.get('port'), } - for key, value in default_settings.items(): + + #defines the name of the database + database_name = 'palbot_db' + + #Connect to PostgreSQL database + try: + #First connect to the default database (template1) + connection = psycopg2.connect(**config, dbname="template1") + connection.autocommit = True + cursor = connection.cursor() + + #Check if the database already exists + cursor.execute(f"SELECT 1 FROM pg_database WHERE datname = '{database_name}'") + result = cursor.fetchone() + + if not result: + cursor.execute(f"CREATE DATABASE {database_name}") + # print(f"Database '{database_name}' created successfully.") + #else: + # print(f"Database '{database_name}' already exists.") + + except psycopg2.Error as e: + print(f"Error: {e}") + finally: + cursor.close() + connection.close() + + #Connect to newly created database + config['dbname'] = database_name + + global CONFIG_PG + CONFIG_PG = config + + try: + connection = psycopg2.connect(**CONFIG_PG) + connection.autocommit = True + cursor = connection.cursor() + + #Create the tables + cursor.execute(''' + CREATE TABLE IF NOT EXISTS servers ( + guild_id VARCHAR(255) NOT NULL, + server_name VARCHAR(255) PRIMARY KEY, + server_host VARCHAR(255) NOT NULL, + rcon_port VARCHAR(32) NOT NULL, + connection_port VARCHAR(32) NOT NULL, + admin_pass VARCHAR(255) NOT NULL + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS user_points ( + user_id VARCHAR(255) PRIMARY KEY, + user_name VARCHAR(255) NOT NULL, + points BIGINT NOT NULL DEFAULT 0, + steam_id VARCHAR(255), + verification_code VARCHAR(255) + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS user_invites ( + user_id VARCHAR(255) PRIMARY KEY, + user_name VARCHAR(255) NOT NULL, + invite_count INT NOT NULL DEFAULT 0 + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS economy_settings ( + setting_key VARCHAR(255) PRIMARY KEY, + setting_value VARCHAR(999) NOT NULL + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS server_events ( + server_name VARCHAR(255) PRIMARY KEY, + channel_id VARCHAR(32) NOT NULL + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS server_queries ( + server_name VARCHAR(255) PRIMARY KEY, + channel_id VARCHAR(32) NOT NULL, + status_message_id VARCHAR(32), + players_message_id VARCHAR(32) + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS players ( + steamid VARCHAR(255) PRIMARY KEY, + name VARCHAR(255), + playeruid VARCHAR(255) + ); + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS cooldowns ( + user_id VARCHAR(255) NOT NULL, + command VARCHAR(255) NOT NULL, + expires_at VARCHAR(50) NOT NULL, + PRIMARY KEY (user_id, command) + ); + ''') + + # Palgame tables + cursor.execute(''' + CREATE TABLE IF NOT EXISTS user_pals ( + user_id VARCHAR(255), + pal_name VARCHAR(255), + experience INT NOT NULL DEFAULT 0, + level INT NOT NULL DEFAULT 1, + PRIMARY KEY (user_id, pal_name) + ); + ''') + + #Enter default settings into the savings system + default_settings = { + "currency_name": "Points", + "invite_reward": "10", + "work_reward_min": "20", + "work_reward_max": "50", + "work_timer": "360", + "daily_reward": "200", + "daily_timer": "86400", + "work_description": '["Your Pals butchered the invaders and earned {earned_points} {currency}!", "Anubis stumbled upon {earned_points} {currency} in the hot tub!"]', + "role_bonuses": '{"Server Booster": 10, "Supporter": 5}', + "vote_slug": "", + "vote_apikey": "", + "vote_reward": "100" + } + for key, value in default_settings.items(): + try: + cursor.execute(''' + INSERT INTO economy_settings (setting_key, setting_value) + VALUES (%s, %s) + ON CONFLICT (setting_key) DO UPDATE + SET setting_value = EXCLUDED.setting_value; + ''', (key, value)) + except psycopg2.Error as e: + print(f"Error inserting the setting {key}: {e}") + + connection.commit() + print("PostgreSql database Complete") + except psycopg2.Error as e: + print(f"Error connecting to PostgreSQL: {e}") + finally: + if connection: + cursor.close() + connection.close() + + + + else: + async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute(''' - INSERT INTO economy_settings (setting_key, setting_value) - VALUES (?, ?) - ON CONFLICT(setting_key) DO NOTHING; - ''', (key, value)) - await db.commit() + CREATE TABLE IF NOT EXISTS servers ( + guild_id TEXT NOT NULL, + server_name TEXT PRIMARY KEY, + server_host TEXT NOT NULL, + rcon_port INTEGER NOT NULL, + connection_port INTEGER NOT NULL, + admin_pass TEXT NOT NULL + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS user_points ( + user_id TEXT PRIMARY KEY, + user_name TEXT NOT NULL, + points INTEGER NOT NULL DEFAULT 0, + steam_id TEXT, + verification_code TEXT + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS user_invites ( + user_id TEXT PRIMARY KEY, + user_name TEXT NOT NULL, + invite_count INTEGER NOT NULL DEFAULT 0 + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS economy_settings ( + setting_key TEXT PRIMARY KEY, + setting_value TEXT NOT NULL + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS server_events ( + server_name TEXT PRIMARY KEY, + channel_id INTEGER NOT NULL + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS server_queries ( + server_name TEXT PRIMARY KEY, + channel_id INTEGER NOT NULL, + status_message_id INTEGER, + players_message_id INTEGER + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS players ( + steamid TEXT PRIMARY KEY, + name TEXT NOT NULL, + playeruid TEXT NOT NULL + ) + ''') + await db.execute(''' + CREATE TABLE IF NOT EXISTS cooldowns ( + user_id TEXT NOT NULL, + command TEXT NOT NULL, + expires_at TIMESTAMP NOT NULL, + PRIMARY KEY (user_id, command) + ) + ''') + # Palgame tables + await db.execute(''' + CREATE TABLE IF NOT EXISTS user_pals ( + user_id TEXT NOT NULL, + pal_name TEXT NOT NULL, + experience INTEGER DEFAULT 0, + level INTEGER DEFAULT 1, + PRIMARY KEY (user_id, pal_name) + ) + ''') + # Settings for the economy system + default_settings = { + "currency_name": "Points", + "invite_reward": "10", + "work_reward_min": "20", + "work_reward_max": "50", + "work_timer": "360", + "daily_reward": "200", + "daily_timer": "86400", + "work_description": '["Your Pals butchered the invaders and earned {earned_points} {currency}!", "Anubis stumbled upon {earned_points} {currency} in the hot tub!"]', + "role_bonuses": '{"Server Booster": 10, "Supporter": 5}', + "vote_slug": "", + "vote_apikey": "", + "vote_reward": "100" + } + for key, value in default_settings.items(): + await db.execute(''' + INSERT INTO economy_settings (setting_key, setting_value) + VALUES (?, ?) + ON CONFLICT(setting_key) DO NOTHING; + ''', (key, value)) + await db.commit() + print("SqlLite database Complete") + + # Server Management async def add_server(guild_id, server_name, server_host, rcon_port, connection_port, admin_pass): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO servers (guild_id, server_name, server_host, rcon_port, connection_port, admin_pass) - VALUES (?, ?, ?, ?, ?, ?) - ''', (guild_id, server_name, server_host, rcon_port, connection_port, admin_pass)) - await db.commit() - + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(sql.SQL(''' + INSERT INTO servers (guild_id, server_name, server_host, rcon_port, connection_port, admin_pass) + VALUES (%s, %s, %s, %s, %s, %s) + '''), (guild_id, server_name, server_host, rcon_port, connection_port, admin_pass)) + conn.commit() + except psycopg2.Error as e: + print(f"Error inserting server: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO servers (guild_id, server_name, server_host, rcon_port, connection_port, admin_pass) + VALUES (?, ?, ?, ?, ?, ?) + ''', (guild_id, server_name, server_host, rcon_port, connection_port, admin_pass)) + await db.commit() + + async def remove_server(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute("DELETE FROM servers WHERE server_name = ?", (server_name,)) - await db.commit() - return cursor.rowcount > 0 - + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("DELETE FROM servers WHERE server_name = %s", (server_name,)) + conn.commit() + return cursor.rowcount > 0 + except psycopg2.Error as e: + print(f"Error removing server: {e}") + return False + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute("DELETE FROM servers WHERE server_name = ?", (server_name,)) + await db.commit() + return cursor.rowcount > 0 + async def server_autocomplete(): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute("SELECT server_name FROM servers") - servers = await cursor.fetchall() - return [server[0] for server in servers] - + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("SELECT server_name FROM servers") + servers = cursor.fetchall() + return [server[0] for server in servers] + except psycopg2.Error as e: + print(f"Error fetching server names: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute("SELECT server_name FROM servers") + servers = await cursor.fetchall() + return [server[0] for server in servers] + + async def get_server_details(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT server_host, rcon_port, admin_pass FROM servers WHERE server_name = ?', (server_name,)) - result = await cursor.fetchone() - return result + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT server_host, rcon_port, admin_pass FROM servers WHERE server_name = %s', (server_name,)) + result = cursor.fetchone() + return result + except psycopg2.Error as e: + print(f"Error fetching server details: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT server_host, rcon_port, admin_pass FROM servers WHERE server_name = ?', (server_name,)) + result = await cursor.fetchone() + return result + async def edit_server_details(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT server_host, rcon_port, connection_port, admin_pass FROM servers WHERE server_name = ?', (server_name,)) - result = await cursor.fetchone() - return result + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT server_host, rcon_port, connection_port, admin_pass FROM servers WHERE server_name = %s', (server_name,)) + result = cursor.fetchone() + return result + except psycopg2.Error as e: + print(f"Error fetching server details: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT server_host, rcon_port, connection_port, admin_pass FROM servers WHERE server_name = ?', (server_name,)) + result = await cursor.fetchone() + return result async def update_server_details(old_server_name, new_server_name, server_host, rcon_port, connection_port, admin_pass): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - UPDATE servers - SET server_name = ?, server_host = ?, rcon_port = ?, connection_port = ?, admin_pass = ? - WHERE server_name = ? - ''', (new_server_name, server_host, rcon_port, connection_port, admin_pass, old_server_name)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + UPDATE servers + SET server_name = %s, server_host = %s, rcon_port = %s, connection_port = %s, admin_pass = %s + WHERE server_name = %s + ''', (new_server_name, server_host, rcon_port, connection_port, admin_pass, old_server_name)) + conn.commit() + except psycopg2.Error as e: + print(f"Error updating server details: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + UPDATE servers + SET server_name = ?, server_host = ?, rcon_port = ?, connection_port = ?, admin_pass = ? + WHERE server_name = ? + ''', (new_server_name, server_host, rcon_port, connection_port, admin_pass, old_server_name)) + await db.commit() + async def get_connection_port(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT connection_port FROM servers WHERE server_name = ?', (server_name,)) - result = await cursor.fetchone() - return result[0] if result else None + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT connection_port FROM servers WHERE server_name = %s', (server_name,)) + result = cursor.fetchone() + return result[0] if result else None + except psycopg2.Error as e: + print(f"Error fetching connection port: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT connection_port FROM servers WHERE server_name = ?', (server_name,)) + result = await cursor.fetchone() + return result[0] if result else None + # Admin Functionality async def add_points(user_id, user_name, points): if points < 0: raise ValueError("Points to add cannot be negative.") - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO user_points (user_id, user_name, points) - VALUES (?, ?, ?) - ON CONFLICT(user_id) DO UPDATE SET points = points + excluded.points, user_name = excluded.user_name; - ''', (user_id, user_name, points)) - await db.commit() + + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO user_points (user_id, user_name, points) + VALUES (%s, %s, %s) + ON CONFLICT(user_id) DO UPDATE + SET points = user_points.points + excluded.points, user_name = excluded.user_name; + ''', (user_id, user_name, points)) + conn.commit() + except psycopg2.Error as e: + print(f"Error adding points: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO user_points (user_id, user_name, points) + VALUES (?, ?, ?) + ON CONFLICT(user_id) DO UPDATE SET points = points + excluded.points, user_name = excluded.user_name; + ''', (user_id, user_name, points)) + await db.commit() + async def set_points(user_id, user_name, points): if points < 0: points = 0 - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO user_points (user_id, user_name, points) - VALUES (?, ?, ?) - ON CONFLICT(user_id) DO UPDATE SET points = excluded.points, user_name = excluded.user_name; - ''', (user_id, user_name, points)) - await db.commit() + + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO user_points (user_id, user_name, points) + VALUES (%s, %s, %s) + ON CONFLICT(user_id) DO UPDATE SET points = excluded.points, user_name = excluded.user_name; + ''', (user_id, user_name, points)) + conn.commit() + except psycopg2.Error as e: + print(f"Error setting points: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO user_points (user_id, user_name, points) + VALUES (?, ?, ?) + ON CONFLICT(user_id) DO UPDATE SET points = excluded.points, user_name = excluded.user_name; + ''', (user_id, user_name, points)) + await db.commit() async def get_points(user_id: str, user_name: str) -> tuple: - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT user_name, points FROM user_points WHERE user_id = ?', (user_id,)) - result = await cursor.fetchone() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT user_name, points FROM user_points WHERE user_id = %s', (user_id,)) + result = cursor.fetchone() - if not result: - await db.execute('INSERT INTO user_points (user_id, user_name, points) VALUES (?, ?, 0)', (user_id, user_name)) - await db.commit() - result = (user_name, 0) + if not result: + cursor.execute('INSERT INTO user_points (user_id, user_name, points) VALUES (%s, %s, 0)', (user_id, user_name)) + conn.commit() + result = (user_name, 0) - return result + return result + except psycopg2.Error as e: + print(f"Error fetching points: {e}") + return (None, 0) + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT user_name, points FROM user_points WHERE user_id = ?', (user_id,)) + result = await cursor.fetchone() + + if not result: + await db.execute('INSERT INTO user_points (user_id, user_name, points) VALUES (?, ?, 0)', (user_id, user_name)) + await db.commit() + result = (user_name, 0) + + return result # For the leaderboard async def get_top_points(limit=10): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT user_name, points FROM user_points ORDER BY points DESC LIMIT ?', (limit,)) - result = await cursor.fetchall() - return result + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT user_name, points FROM user_points ORDER BY points DESC LIMIT %s', (limit,)) + result = cursor.fetchall() + return result + except psycopg2.Error as e: + print(f"Error fetching top points: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT user_name, points FROM user_points ORDER BY points DESC LIMIT ?', (limit,)) + result = await cursor.fetchall() + return result + async def get_user_rank(user_id): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT COUNT(*) + 1 - FROM user_points - WHERE points > (SELECT points FROM user_points WHERE user_id = ?) - ''', (user_id,)) - result = await cursor.fetchone() - return result[0] if result else 0 + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT COUNT(*) + 1 + FROM user_points + WHERE points > (SELECT points FROM user_points WHERE user_id = %s) + ''', (user_id,)) + result = cursor.fetchone() + return result[0] if result else 0 + except psycopg2.Error as e: + print(f"Error fetching user rank: {e}") + return 0 + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT COUNT(*) + 1 + FROM user_points + WHERE points > (SELECT points FROM user_points WHERE user_id = ?) + ''', (user_id,)) + result = await cursor.fetchone() + return result[0] if result else 0 + # Steam Link async def link_steam_account(user_id, steam_id, verification_code=None): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - UPDATE user_points SET steam_id = ?, verification_code = ? - WHERE user_id = ? - ''', (steam_id, verification_code, user_id)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + UPDATE user_points SET steam_id = %s, verification_code = %s + WHERE user_id = %s + ''', (steam_id, verification_code, user_id)) + conn.commit() + except psycopg2.Error as e: + print(f"Error linking Steam account: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + UPDATE user_points SET steam_id = ?, verification_code = ? + WHERE user_id = ? + ''', (steam_id, verification_code, user_id)) + await db.commit() async def get_steam_id(user_id): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT steam_id FROM user_points WHERE user_id = ?', (user_id,)) - result = await cursor.fetchone() - return result[0] if result else None + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT steam_id FROM user_points WHERE user_id = %s', (user_id,)) + result = cursor.fetchone() + return result[0] if result else None + except psycopg2.Error as e: + print(f"Error fetching Steam ID: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT steam_id FROM user_points WHERE user_id = ?', (user_id,)) + result = await cursor.fetchone() + return result[0] if result else None # Invites tracking async def add_invite(user_id, user_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO user_invites (user_id, user_name, invite_count) - VALUES (?, ?, 1) - ON CONFLICT(user_id) DO UPDATE SET invite_count = invite_count + 1, user_name = excluded.user_name; - ''', (user_id, user_name)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO user_invites (user_id, user_name, invite_count) + VALUES (%s, %s, 1) + ON CONFLICT(user_id) DO UPDATE SET invite_count = invite_count + 1, user_name = excluded.user_name; + ''', (user_id, user_name)) + conn.commit() + except psycopg2.Error as e: + print(f"Error adding invite: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO user_invites (user_id, user_name, invite_count) + VALUES (?, ?, 1) + ON CONFLICT(user_id) DO UPDATE SET invite_count = invite_count + 1, user_name = excluded.user_name; + ''', (user_id, user_name)) + await db.commit() + async def get_invite_count(user_id): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT user_name, invite_count FROM user_invites WHERE user_id = ?', (user_id,)) - result = await cursor.fetchone() - return result if result else (None, 0) + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT user_name, invite_count FROM user_invites WHERE user_id = %s', (user_id,)) + result = cursor.fetchone() + return result if result else (None, 0) + except psycopg2.Error as e: + print(f"Error fetching invite count: {e}") + return (None, 0) + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT user_name, invite_count FROM user_invites WHERE user_id = ?', (user_id,)) + result = await cursor.fetchone() + return result if result else (None, 0) async def get_top_invites(limit=10): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT user_name, invite_count FROM user_invites ORDER BY invite_count DESC LIMIT ? - ''', (limit,)) - result = await cursor.fetchall() - return result + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT user_name, invite_count FROM user_invites ORDER BY invite_count DESC LIMIT %s + ''', (limit,)) + result = cursor.fetchall() + return result + except psycopg2.Error as e: + print(f"Error fetching top invites: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT user_name, invite_count FROM user_invites ORDER BY invite_count DESC LIMIT ? + ''', (limit,)) + result = await cursor.fetchall() + return result async def update_discord_username(user_id, user_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - UPDATE user_points SET user_name = ? WHERE user_id = ? - ''', (user_name, user_id)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + UPDATE user_points SET user_name = %s WHERE user_id = %s + ''', (user_name, user_id)) + conn.commit() + except psycopg2.Error as e: + print(f"Error updating Discord username: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + UPDATE user_points SET user_name = ? WHERE user_id = ? + ''', (user_name, user_id)) + await db.commit() # Economy Settings async def update_economy_setting(key, value): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO economy_settings (setting_key, setting_value) - VALUES (?, ?) - ON CONFLICT(setting_key) DO UPDATE SET setting_value = excluded.setting_value - ''', (key, value)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO economy_settings (setting_key, setting_value) + VALUES (%s, %s) + ON CONFLICT(setting_key) DO UPDATE SET setting_value = excluded.setting_value + ''', (key, value)) + conn.commit() + except psycopg2.Error as e: + print(f"Error updating economy setting: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO economy_settings (setting_key, setting_value) + VALUES (?, ?) + ON CONFLICT(setting_key) DO UPDATE SET setting_value = excluded.setting_value + ''', (key, value)) + await db.commit() async def get_economy_setting(key): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT setting_value FROM economy_settings WHERE setting_key = ?', (key,)) - result = await cursor.fetchone() - return result[0] if result else None + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT setting_value FROM economy_settings WHERE setting_key = %s', (key,)) + result = cursor.fetchone() + return result[0] if result else None + except psycopg2.Error as e: + print(f"Error fetching economy setting: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT setting_value FROM economy_settings WHERE setting_key = ?', (key,)) + result = await cursor.fetchone() + return result[0] if result else None async def reset_economy_settings(): await update_economy_setting("currency_name", "Points") @@ -275,100 +758,283 @@ async def reset_economy_settings(): # Server Events async def add_event_channel(server_name, channel_id): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO server_events (server_name, channel_id) - VALUES (?, ?) - ON CONFLICT(server_name) DO UPDATE SET channel_id = excluded.channel_id; - ''', (server_name, channel_id)) - await db.commit() - return True + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO server_events (server_name, channel_id) + VALUES (%s, %s) + ON CONFLICT(server_name) DO UPDATE SET channel_id = excluded.channel_id; + ''', (server_name, channel_id)) + conn.commit() + return True + except psycopg2.Error as e: + print(f"Error adding event channel: {e}") + return False + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO server_events (server_name, channel_id) + VALUES (?, ?) + ON CONFLICT(server_name) DO UPDATE SET channel_id = excluded.channel_id; + ''', (server_name, channel_id)) + await db.commit() + return True async def remove_event_channel(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute("DELETE FROM server_events WHERE server_name = ?", (server_name,)) - await db.commit() - return cursor.rowcount > 0 + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("DELETE FROM server_events WHERE server_name = %s", (server_name,)) + conn.commit() + return cursor.rowcount > 0 + except psycopg2.Error as e: + print(f"Error removing event channel: {e}") + return False + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute("DELETE FROM server_events WHERE server_name = ?", (server_name,)) + await db.commit() + return cursor.rowcount > 0 async def get_event_channel(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT channel_id FROM server_events WHERE server_name = ?', (server_name,)) - result = await cursor.fetchone() - return result[0] if result else None + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT channel_id FROM server_events WHERE server_name = %s', (server_name,)) + result = cursor.fetchone() + return result[0] if result else None + except psycopg2.Error as e: + print(f"Error fetching event channel: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT channel_id FROM server_events WHERE server_name = ?', (server_name,)) + result = await cursor.fetchone() + return result[0] if result else None # Server Query async def add_query_channel(server_name, channel_id, status_message_id, players_message_id): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO server_queries (server_name, channel_id, status_message_id, players_message_id) - VALUES (?, ?, ?, ?) - ON CONFLICT(server_name) DO UPDATE SET channel_id = excluded.channel_id, status_message_id = excluded.status_message_id, players_message_id = excluded.players_message_id; - ''', (server_name, channel_id, status_message_id, players_message_id)) - await db.commit() - return True + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO server_queries (server_name, channel_id, status_message_id, players_message_id) + VALUES (%s, %s, %s, %s) + ON CONFLICT(server_name) DO UPDATE SET channel_id = excluded.channel_id, status_message_id = excluded.status_message_id, players_message_id = excluded.players_message_id; + ''', (server_name, channel_id, status_message_id, players_message_id)) + conn.commit() + return True + except psycopg2.Error as e: + print(f"Error adding query channel: {e}") + return False + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO server_queries (server_name, channel_id, status_message_id, players_message_id) + VALUES (?, ?, ?, ?) + ON CONFLICT(server_name) DO UPDATE SET channel_id = excluded.channel_id, status_message_id = excluded.status_message_id, players_message_id = excluded.players_message_id; + ''', (server_name, channel_id, status_message_id, players_message_id)) + await db.commit() + return True async def remove_query_channel(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute("DELETE FROM server_queries WHERE server_name = ?", (server_name,)) - await db.commit() - return cursor.rowcount > 0 + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("DELETE FROM server_queries WHERE server_name = %s", (server_name,)) + conn.commit() + return cursor.rowcount > 0 + except psycopg2.Error as e: + print(f"Error removing query channel: {e}") + return False + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute("DELETE FROM server_queries WHERE server_name = ?", (server_name,)) + await db.commit() + return cursor.rowcount > 0 async def get_query_channel(server_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT channel_id, status_message_id, players_message_id FROM server_queries WHERE server_name = ?', (server_name,)) - result = await cursor.fetchone() - return result if result else (None, None, None) + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT channel_id, status_message_id, players_message_id FROM server_queries WHERE server_name = %s', (server_name,)) + result = cursor.fetchone() + return result if result else (None, None, None) + except psycopg2.Error as e: + print(f"Error fetching query channel: {e}") + return (None, None, None) + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT channel_id, status_message_id, players_message_id FROM server_queries WHERE server_name = ?', (server_name,)) + result = await cursor.fetchone() + return result if result else (None, None, None) # Player Logging async def insert_player_data(steamid, name, playeruid): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO players (steamid, name, playeruid) - VALUES (?, ?, ?) - ON CONFLICT(steamid) DO UPDATE SET - name=excluded.name, playeruid=excluded.playeruid - ''', (steamid, name, playeruid)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO players (steamid, name, playeruid) + VALUES (%s, %s, %s) + ON CONFLICT(steamid) DO UPDATE SET + name=excluded.name, playeruid=excluded.playeruid + ''', (steamid, name, playeruid)) + conn.commit() + except psycopg2.Error as e: + print(f"Error inserting player data: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO players (steamid, name, playeruid) + VALUES (?, ?, ?) + ON CONFLICT(steamid) DO UPDATE SET + name=excluded.name, playeruid=excluded.playeruid + ''', (steamid, name, playeruid)) + await db.commit() async def get_player_steamids(current: str): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute("SELECT steamid FROM players WHERE steamid LIKE ?", (f'%{current}%',)) - steamids = await cursor.fetchall() - return [row[0] for row in steamids] + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("SELECT steamid FROM players WHERE steamid LIKE %s", (f'%{current}%',)) + steamids = cursor.fetchall() + return [row[0] for row in steamids] + except psycopg2.Error as e: + print(f"Error fetching player steam IDs: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute("SELECT steamid FROM players WHERE steamid LIKE ?", (f'%{current}%',)) + steamids = await cursor.fetchall() + return [row[0] for row in steamids] async def get_player_names(current: str): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute("SELECT name FROM players WHERE name LIKE ?", (f'%{current}%',)) - names = await cursor.fetchall() - return [row[0] for row in names] + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("SELECT name FROM players WHERE name LIKE %s", (f'%{current}%',)) + names = cursor.fetchall() + return [row[0] for row in names] + except psycopg2.Error as e: + print(f"Error fetching player names: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute("SELECT name FROM players WHERE name LIKE ?", (f'%{current}%',)) + names = await cursor.fetchall() + return [row[0] for row in names] async def get_player_profile(identifier: str): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT steamid, name, playeruid - FROM players - WHERE steamid = ? OR name = ? - ''', (identifier, identifier)) - return await cursor.fetchone() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT steamid, name, playeruid + FROM players + WHERE steamid = %s OR name = %s + ''', (identifier, identifier)) + return cursor.fetchone() + except psycopg2.Error as e: + print(f"Error fetching player profile: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT steamid, name, playeruid + FROM players + WHERE steamid = ? OR name = ? + ''', (identifier, identifier)) + return await cursor.fetchone() # Cooldown tracking for economy commands # Will implement to Pal Game later on. async def set_cooldown(user_id, command, expires_at): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO cooldowns (user_id, command, expires_at) - VALUES (?, ?, ?) - ON CONFLICT(user_id, command) DO UPDATE SET expires_at = excluded.expires_at; - ''', (user_id, command, expires_at)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO cooldowns (user_id, command, expires_at) + VALUES (%s, %s, %s) + ON CONFLICT(user_id, command) DO UPDATE SET expires_at = excluded.expires_at; + ''', (user_id, command, expires_at)) + conn.commit() + except psycopg2.Error as e: + print(f"Error setting cooldown: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO cooldowns (user_id, command, expires_at) + VALUES (?, ?, ?) + ON CONFLICT(user_id, command) DO UPDATE SET expires_at = excluded.expires_at; + ''', (user_id, command, expires_at)) + await db.commit() async def get_cooldown(user_id, command): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT expires_at FROM cooldowns WHERE user_id = ? AND command = ?', (user_id, command)) - result = await cursor.fetchone() - return result[0] if result else None + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT expires_at FROM cooldowns WHERE user_id = %s AND command = %s', (user_id, command)) + result = cursor.fetchone() + return result[0] if result else None + except psycopg2.Error as e: + print(f"Error fetching cooldown: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT expires_at FROM cooldowns WHERE user_id = ? AND command = ?', (user_id, command)) + result = await cursor.fetchone() + return result[0] if result else None async def clear_expired_cooldowns(): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute("DELETE FROM cooldowns WHERE expires_at < datetime('now')") - await db.commit() \ No newline at end of file + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute("DELETE FROM cooldowns WHERE expires_at::timestamp < NOW()") + conn.commit() + except psycopg2.Error as e: + print(f"Error clearing expired cooldowns: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute("DELETE FROM cooldowns WHERE expires_at < datetime('now')") + await db.commit() \ No newline at end of file diff --git a/utils/kitutility.py b/utils/kitutility.py index 9c5ff91..62bc194 100644 --- a/utils/kitutility.py +++ b/utils/kitutility.py @@ -1,65 +1,240 @@ import nextcord import aiosqlite import os +import psycopg2 +from urllib.parse import urlparse +from psycopg2 import sql +import utils.settings as settings from utils.translations import t DATABASE_PATH = os.path.join('data', 'kits.db') +CONFIG_KITS_PG = '' + + async def init_kitdb(): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - CREATE TABLE IF NOT EXISTS kits ( - name TEXT PRIMARY KEY, - commands TEXT, - description TEXT, - price INTEGER - ) - ''') - await db.commit() + #Check if the connection string is available + if settings.connection_string: + + def parse_connection_url(url): + result = urlparse(url) + return { + 'user': result.username, + 'password': result.password, + 'host': result.hostname, + 'port': result.port or 5432, # PostgreSQL default port is 5432 + } + + #Parse the connection string + conn_params = parse_connection_url(settings.connection_string) + + #Configure connection parameters + config_kits = { + 'user': conn_params.get('user'), + 'password': conn_params.get('password'), + 'host': conn_params.get('host'), + 'port': conn_params.get('port'), + } + + #defines the name of the database + database_name = 'kits_db' + + #Connect to PostgreSQL database + try: + #First connect to the default database (template1) + connection = psycopg2.connect(**config_kits, dbname="template1") + connection.autocommit = True + cursor = connection.cursor() + + #Check if the database already exists + cursor.execute(f"SELECT 1 FROM pg_database WHERE datname = '{database_name}'") + result = cursor.fetchone() + + if not result: + cursor.execute(f"CREATE DATABASE {database_name}") + # print(f"Database '{database_name}' created successfully.") + #else: + # print(f"Database '{database_name}' already exists.") + + except psycopg2.Error as e: + print(f"Error: {e}") + finally: + cursor.close() + connection.close() + + #Connect to newly created database + config_kits['dbname'] = database_name + + global CONFIG_KITS_PG + CONFIG_KITS_PG = config_kits + + try: + connection = psycopg2.connect(**CONFIG_KITS_PG) + connection.autocommit = True + cursor = connection.cursor() + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS kits ( + name VARCHAR(255) PRIMARY KEY, + commands VARCHAR(255), + description VARCHAR(255), + price INTEGER + ) + ''') + except psycopg2.Error as e: + print(f"Error connecting to PostgreSQL: {e}") + finally: + if connection: + cursor.close() + connection.close() + else: + + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + CREATE TABLE IF NOT EXISTS kits ( + name TEXT PRIMARY KEY, + commands TEXT, + description TEXT, + price INTEGER + ) + ''') + await db.commit() + async def get_kit(kit_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT commands, description, price FROM kits WHERE name = ?', (kit_name,)) - return await cursor.fetchone() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_KITS_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT commands, description, price FROM kits WHERE name = %s', (kit_name,)) + return cursor.fetchone() + except psycopg2.Error as e: + print(f"Error fetching kit: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT commands, description, price FROM kits WHERE name = ?', (kit_name,)) + return await cursor.fetchone() + + async def save_kit(kit_name, commands, description, price): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO kits (name, commands, description, price) - VALUES (?, ?, ?, ?) - ON CONFLICT(name) DO UPDATE SET commands=excluded.commands, description=excluded.description, price=excluded.price - ''', (kit_name, commands, description, int(price))) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_KITS_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO kits (name, commands, description, price) + VALUES (%s, %s, %s, %s) + ON CONFLICT(name) DO UPDATE SET commands=excluded.commands, description=excluded.description, price=excluded.price + ''', (kit_name, commands, description, int(price))) + conn.commit() + except psycopg2.Error as e: + print(f"Error saving kit: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO kits (name, commands, description, price) + VALUES (?, ?, ?, ?) + ON CONFLICT(name) DO UPDATE SET commands=excluded.commands, description=excluded.description, price=excluded.price + ''', (kit_name, commands, description, int(price))) + await db.commit() + + async def delete_kit(kit_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute('DELETE FROM kits WHERE name = ?', (kit_name,)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_KITS_PG) + try: + with conn.cursor() as cursor: + cursor.execute('DELETE FROM kits WHERE name = %s', (kit_name,)) + conn.commit() + except psycopg2.Error as e: + print(f"Error deleting kit: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute('DELETE FROM kits WHERE name = ?', (kit_name,)) + await db.commit() + + async def autocomplete_kits(current: str): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT name FROM kits WHERE name LIKE ?', (f'%{current}%',)) - kits = await cursor.fetchall() - return [kit[0] for kit in kits] + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_KITS_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT name FROM kits WHERE name LIKE %s', (f'%{current}%',)) + kits = cursor.fetchall() + return [kit[0] for kit in kits] + except psycopg2.Error as e: + print(f"Error autocompleting kits: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT name FROM kits WHERE name LIKE ?', (f'%{current}%',)) + kits = await cursor.fetchall() + return [kit[0] for kit in kits] + + + async def fetch_all_kits(): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT name, commands, description, price FROM kits') - kits = await cursor.fetchall() - return kits + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_KITS_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT name, commands, description, price FROM kits') + kits = cursor.fetchall() + return kits + except psycopg2.Error as e: + print(f"Error fetching all kits: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT name, commands, description, price FROM kits') + kits = await cursor.fetchall() + return kits async def load_shop_items(): shop_items = {} - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute('SELECT name, description, price FROM kits WHERE price > 0') - kits = await cursor.fetchall() - for kit in kits: - commands, description, price = await get_kit(kit[0]) - shop_items[kit[0]] = { - "commands": commands, - "description": description, - "price": price - } + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_KITS_PG) + try: + with conn.cursor() as cursor: + cursor.execute('SELECT name, description, price FROM kits WHERE price > 0') + kits = cursor.fetchall() + for kit in kits: + commands, description, price = await get_kit(kit[0]) + shop_items[kit[0]] = { + "commands": commands, + "description": description, + "price": price + } + except psycopg2.Error as e: + print(f"Error loading shop items: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT name, description, price FROM kits WHERE price > 0') + kits = await cursor.fetchall() + for kit in kits: + commands, description, price = await get_kit(kit[0]) + shop_items[kit[0]] = { + "commands": commands, + "description": description, + "price": price + } return shop_items class KitModal(nextcord.ui.Modal): diff --git a/utils/palgame.py b/utils/palgame.py index 0feb94d..9f99ad9 100644 --- a/utils/palgame.py +++ b/utils/palgame.py @@ -1,69 +1,180 @@ import aiosqlite import os +import psycopg2 +from utils.database import CONFIG_PG +import utils.settings as settings DATABASE_PATH = os.path.join('data', 'palbot.db') async def add_experience(user_id, pal_name, experience_gained): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute('''UPDATE user_pals SET experience = experience + ? WHERE user_id = ? AND pal_name = ?;''', (experience_gained, user_id, pal_name)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + UPDATE user_pals SET experience = experience + %s + WHERE user_id = %s AND pal_name = %s; + ''', (experience_gained, user_id, pal_name)) + conn.commit() + except psycopg2.Error as e: + print(f"Error adding experience: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + UPDATE user_pals SET experience = experience + ? + WHERE user_id = ? AND pal_name = ?; + ''', (experience_gained, user_id, pal_name)) + await db.commit() async def add_pal(user_id, pal_name, experience=0, level=1): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - INSERT INTO user_pals (user_id, pal_name, experience, level) - VALUES (?, ?, ?, ?) - ON CONFLICT(user_id, pal_name) DO UPDATE - SET experience = excluded.experience, level = excluded.level; - ''', (user_id, pal_name, experience, level)) - await db.commit() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + INSERT INTO user_pals (user_id, pal_name, experience, level) + VALUES (%s, %s, %s, %s) + ON CONFLICT(user_id, pal_name) DO UPDATE + SET experience = EXCLUDED.experience, level = EXCLUDED.level; + ''', (user_id, pal_name, experience, level)) + conn.commit() + except psycopg2.Error as e: + print(f"Error adding pal: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + await db.execute(''' + INSERT INTO user_pals (user_id, pal_name, experience, level) + VALUES (?, ?, ?, ?) + ON CONFLICT(user_id, pal_name) DO UPDATE + SET experience = excluded.experience, level = excluded.level; + ''', (user_id, pal_name, experience, level)) + await db.commit() async def get_pals(user_id): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT pal_name, level, experience FROM user_pals WHERE user_id = ? - ''', (user_id,)) - pals = await cursor.fetchall() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT pal_name, level, experience FROM user_pals + WHERE user_id = %s; + ''', (user_id,)) + pals = cursor.fetchall() + return pals + except psycopg2.Error as e: + print(f"Error fetching pals: {e}") + return [] + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT pal_name, level, experience FROM user_pals + WHERE user_id = ?; + ''', (user_id,)) + pals = await cursor.fetchall() return pals async def level_up(user_id, pal_name): - # reworked leveling system... - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT level, experience FROM user_pals - WHERE user_id = ? AND pal_name = ?; - ''', (user_id, pal_name)) - pal = await cursor.fetchone() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT level, experience FROM user_pals + WHERE user_id = %s AND pal_name = %s; + ''', (user_id, pal_name)) + pal = cursor.fetchone() - if pal: - level = pal[0] - experience = pal[1] - - required_experience = 1000 + (level - 1) * 200 + if pal: + level, experience = pal + required_experience = 1000 + (level - 1) * 200 - while experience >= required_experience: - level += 1 - experience -= required_experience - required_experience = 1000 + (level - 1) * 200 + while experience >= required_experience: + level += 1 + experience -= required_experience + required_experience = 1000 + (level - 1) * 200 - await db.execute(''' - UPDATE user_pals - SET level = ?, experience = ? + cursor.execute(''' + UPDATE user_pals + SET level = %s, experience = %s + WHERE user_id = %s AND pal_name = %s; + ''', (level, experience, user_id, pal_name)) + conn.commit() + except psycopg2.Error as e: + print(f"Error leveling up pal: {e}") + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT level, experience FROM user_pals WHERE user_id = ? AND pal_name = ?; - ''', (level, experience, user_id, pal_name)) - await db.commit() + ''', (user_id, pal_name)) + pal = await cursor.fetchone() + + if pal: + level, experience = pal + required_experience = 1000 + (level - 1) * 200 + + while experience >= required_experience: + level += 1 + experience -= required_experience + required_experience = 1000 + (level - 1) * 200 + + await db.execute(''' + UPDATE user_pals + SET level = ?, experience = ? + WHERE user_id = ? AND pal_name = ?; + ''', (level, experience, user_id, pal_name)) + await db.commit() async def get_stats(user_id, pal_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT level, experience FROM user_pals - WHERE user_id = ? AND pal_name = ?; - ''', (user_id, pal_name)) - return await cursor.fetchone() + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT level, experience FROM user_pals + WHERE user_id = %s AND pal_name = %s; + ''', (user_id, pal_name)) + return cursor.fetchone() + except psycopg2.Error as e: + print(f"Error fetching stats: {e}") + return None + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT level, experience FROM user_pals + WHERE user_id = ? AND pal_name = ?; + ''', (user_id, pal_name)) + return await cursor.fetchone() async def check_pal(user_id, pal_name): - async with aiosqlite.connect(DATABASE_PATH) as db: - cursor = await db.execute(''' - SELECT 1 FROM user_pals WHERE user_id = ? AND pal_name = ? - ''', (user_id, pal_name)) - return await cursor.fetchone() is not None \ No newline at end of file + if settings.connection_string: + conn = psycopg2.connect(**CONFIG_PG) + try: + with conn.cursor() as cursor: + cursor.execute(''' + SELECT 1 FROM user_pals + WHERE user_id = %s AND pal_name = %s; + ''', (user_id, pal_name)) + return cursor.fetchone() is not None + except psycopg2.Error as e: + print(f"Error checking pal: {e}") + return False + finally: + conn.close() + else: + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute(''' + SELECT 1 FROM user_pals + WHERE user_id = ? AND pal_name = ?; + ''', (user_id, pal_name)) + return await cursor.fetchone() is not None \ No newline at end of file diff --git a/utils/settings.py b/utils/settings.py index 81e99a5..963617a 100644 --- a/utils/settings.py +++ b/utils/settings.py @@ -11,6 +11,7 @@ steam_api_key = os.getenv("STEAM_API_KEY", "No key found") bot_language = os.getenv("BOT_LANGUAGE", "en") whitelist_check = os.getenv('GUILD_WHITELIST') +connection_string = os.getenv("BOT_POSTGRESQL_STRING_CONNECTION",'') # Logic for the guild whitelist. async def check_whitelist(bot):