From 2bbfd807096044d60307b8a723b00e036d9cc03f Mon Sep 17 00:00:00 2001 From: Comlud Date: Tue, 19 Dec 2023 00:45:17 +0100 Subject: [PATCH 1/8] first gambling commit --- .gitignore | 5 +- requirements.txt | 1 + src/__main__.py | 3 +- src/cogs/gamble.py | 152 ++++++++++++++++++++++++++++++++++++++ src/util/user_database.py | 31 ++++++++ 5 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 src/cogs/gamble.py create mode 100644 src/util/user_database.py diff --git a/.gitignore b/.gitignore index 4be3a4e..b757c55 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,7 @@ venv.bak/ # mypy .mypy_cache/ /.vscode -token.txt \ No newline at end of file +token.txt + +# database +*.db \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index eda4958..18ee7af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ fuzzywuzzy==0.18.0 discord.py==2.1.0 aiohttp==3.8.5 python-Levenshtein==0.12.2 +datetime==5.4 diff --git a/src/__main__.py b/src/__main__.py index bc02cc5..261abd2 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -29,7 +29,8 @@ async def on_ready(): "src.cogs.admin", "src.cogs.error_handler", "src.cogs.snipe", - "src.cogs.modmail" + "src.cogs.modmail", + "src.cogs.gamble" ] for cog in bot.user_cogs: print(f"Loading {cog}...") diff --git a/src/cogs/gamble.py b/src/cogs/gamble.py new file mode 100644 index 0000000..918f381 --- /dev/null +++ b/src/cogs/gamble.py @@ -0,0 +1,152 @@ +import random +import time + +from discord.ext import commands +import discord +from discord.ext.commands import Context +from discord import Member +from datetime import datetime + +from src.util.user_database import * + + +daily_amount = 10 + +class Gamble(commands.Cog, name="Gamble"): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_command_error(self, ctx: Context, error): + try: + if isinstance(error, commands.MissingRequiredArgument): + await ctx.send('Invalid input.') + if isinstance(error, commands.MissingPermissions): + await ctx.send('You do not have permission to use this command.') + if isinstance(error, commands.BadUnionArgument): + await ctx.send('Invalid input.') + except Exception as error: + print(error) + + @commands.hybrid_command(with_app_command=True) + async def bet(self, ctx: Context, amount_to_bet: int): + """ + Place a bet (50/50). Enter the amount to bet. + """ + user_database_check_if_user_exists_otherwise_add(ctx.author.id) + + if amount_to_bet == None: + await ctx.send('You need to enter the amount to bet.', ephemeral=True) + return + + amount_in_wallet = user_database_get('money', ctx.author.id) + + if amount_to_bet <= 0: + await ctx.send('You must enter a positive number greater than 0.', ephemeral=True) + return + if amount_to_bet > amount_in_wallet: + await ctx.send('You don\'t have enough money.', ephemeral=True) + return + + won = random.randint(1, 2) == 1 + + # Update wallet. + amount_result = amount_in_wallet + (amount_to_bet if won else -amount_to_bet) + user_database_set('money', amount_result, ctx.author.id) + + if won: + embed = discord.Embed(title='You won!', color=discord.Color.green()) + embed.add_field(name=f'{amount_to_bet}$ has been added to your wallet', value=f'You have {amount_result}$') + await ctx.send(embed=embed) + else: + embed = discord.Embed(title='You lost.', color=discord.Color.red()) + embed.add_field(name=f'{amount_to_bet}$ has been removed from your wallet', value=f'You have {amount_result}$') + await ctx.send(embed=embed) + + @commands.hybrid_command(with_app_command=True) + async def wallet(self, ctx: Context, user: Member = None): + """ + Check your wallet. (Optional) Enter another user's ID to view their wallet. + """ + if user is None: + user = ctx.author + + user_database_check_if_user_exists_otherwise_add(user.id) + + embed = discord.Embed(title=f'{user.display_name}\'s wallet', color=discord.Color.blurple()) + embed.set_thumbnail(url='https://cdn.iconscout.com/icon/free/png-512/free-wallet-588-456730.png') + embed.add_field(name='Money', value=f'{user_database_get("money", user.id)}$') + + await ctx.send(embed=embed) + + @commands.hybrid_command(with_app_command=True) + async def daily(self, ctx: Context): + """ + Get a small amount of money, works once per day. + """ + user_database_check_if_user_exists_otherwise_add(ctx.author.id) + + last_daily_timestamp = int(user_database_get('last_daily_timestamp', ctx.author.id)) + current_timestamp = int(time.time()) + seconds_in_a_day = 86400 + seconds_since_last_daily = current_timestamp - last_daily_timestamp + if seconds_since_last_daily < seconds_in_a_day: + formatted_time = datetime.fromtimestamp(seconds_in_a_day - seconds_since_last_daily).strftime('%Hh %Mm %Ss') + await ctx.send(f'You need to wait {formatted_time} before you can use this again.', ephemeral=True) + return + + # Update timestamp and add money to user's wallet. + user_database_set('last_daily_timestamp', current_timestamp, ctx.author.id, commit_changes=False) + user_database_set('money', daily_amount, ctx.author.id, commit_changes=True, add_value_instead=True) + + await ctx.send(f'{ctx.author.mention} {daily_amount}$ has been added to your wallet.') + + @commands.hybrid_command(with_app_command=True) + async def give(self, ctx: Context, user: Member, amount: int): + """ + Transfer money to another member. First argument is user ID. Ssecond argument is amount. + """ + user_database_check_if_user_exists_otherwise_add(ctx.author.id) + + if amount <= 0: + await ctx.send('You must enter a positive number greater than 0.', ephemeral=True) + return + if amount > user_database_get('money', ctx.author.id): + await ctx.send('You don\'t have enough money.', ephemeral=True) + return + + if not user: + await ctx.send('User is not a valid user or not a member of this server.', ephemeral=True) + return + + user_database_check_if_user_exists_otherwise_add(user.id) + + user_database_set('money', -amount, ctx.author.id, commit_changes=False, add_value_instead=True) + user_database_set('money', amount, user.id, commit_changes=True, add_value_instead=True) + + await ctx.send(f'Transferred {amount}$ from {ctx.author.display_name} to {user.display_name}') + + @commands.hybrid_command(with_app_command=True) + async def leaderboard(self, ctx: Context, entries: int = 10): + """ + Show the members with the most money. + """ + # Poor man's clamp. + entries = max(1, min(entries, 50)) + + query = user_database.execute(f'SELECT id, money FROM users ORDER BY money DESC LIMIT ?', [entries]) + + member_list = '' + + for index, entry in enumerate(query.fetchall()): + user_id = entry[0] + user_money = entry[1] + member_list += f'{index + 1}. {self.bot.get_user(user_id).mention} {user_money}$\n' + + embed = discord.Embed(title='Leaderboard', color=discord.Color.blurple()) + embed.add_field(name=f'Showing top {entries} members', value=member_list) + + await ctx.send(embed=embed) + +async def setup(bot): + await bot.add_cog(Gamble(bot)) \ No newline at end of file diff --git a/src/util/user_database.py b/src/util/user_database.py new file mode 100644 index 0000000..ff7531a --- /dev/null +++ b/src/util/user_database.py @@ -0,0 +1,31 @@ +import sqlite3 + +user_database_connection = sqlite3.connect('users.db') +user_database = user_database_connection.cursor() + +user_database.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER, money INTEGER, last_daily_timestamp INTEGER)') +user_database_connection.commit() + +def user_database_get(field_name, user_id): + query = user_database.execute(f'SELECT {field_name} FROM users WHERE id = ?', [user_id]) + return query.fetchone()[0] + +def user_database_set(field_name, value, user_id, commit_changes = True, add_value_instead = False): + user_database.execute(f'UPDATE users SET {field_name} = {(field_name + " +") if add_value_instead else ""} ? WHERE id = ?', [value, user_id]) + if commit_changes: + user_database_connection.commit() + +def user_database_check_if_user_exists_otherwise_add(user_id): + """ + NOTE: This function only checks if a user ID exists in the database, not if the user ID belongs to a valid server member. + """ + # Query number of times user id is found which should be 0 or 1. + query = user_database.execute('SELECT COUNT(*) FROM users WHERE id = ?', [user_id]) + count = query.fetchone()[0] + + # If no user ID was found in database, add user. + if count == 0: + user_database.execute('INSERT INTO users VALUES (?, 0, 0)', [user_id]) + user_database_connection.commit() + elif count > 1: + raise Exception(f'Found multiple copies of user ID ({user_id}) in database.') \ No newline at end of file From 875e3caa7030c265c07723b6f8b7c66b78f2fc33 Mon Sep 17 00:00:00 2001 From: Comlud Date: Sat, 23 Dec 2023 15:23:09 +0100 Subject: [PATCH 2/8] gambling related improvements Still need to fix /daily and turn the wallet icon into a server sticker. --- requirements.txt | 1 - src/__main__.py | 4 ++ src/cogs/gamble.py | 95 +++++++++++++++++++-------------------- src/config.py | 4 ++ src/init.sql | 5 +++ src/util/db.py | 38 ++++++++++++++++ src/util/user_database.py | 31 ------------- 7 files changed, 98 insertions(+), 80 deletions(-) create mode 100644 src/init.sql create mode 100644 src/util/db.py delete mode 100644 src/util/user_database.py diff --git a/requirements.txt b/requirements.txt index 18ee7af..eda4958 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,3 @@ fuzzywuzzy==0.18.0 discord.py==2.1.0 aiohttp==3.8.5 python-Levenshtein==0.12.2 -datetime==5.4 diff --git a/src/__main__.py b/src/__main__.py index 261abd2..5d3b42f 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -2,6 +2,8 @@ import discord from discord.ext import commands from src.util.blacklist import blacklist +from src.util.db import Database +from src import config as conf def prefix(bot, message): return [".", "++"] @@ -13,6 +15,8 @@ def prefix(bot, message): @bot.event async def on_ready(): + bot.user_db = Database(conf.user_db_path) + bot.user_cogs = [ # "src.cogs.verona", "src.cogs.ping", diff --git a/src/cogs/gamble.py b/src/cogs/gamble.py index 918f381..25419ec 100644 --- a/src/cogs/gamble.py +++ b/src/cogs/gamble.py @@ -7,24 +7,22 @@ from discord import Member from datetime import datetime -from src.util.user_database import * - - -daily_amount = 10 +from src import config as conf class Gamble(commands.Cog, name="Gamble"): def __init__(self, bot): self.bot = bot + self.db = bot.user_db @commands.Cog.listener() async def on_command_error(self, ctx: Context, error): try: if isinstance(error, commands.MissingRequiredArgument): - await ctx.send('Invalid input.') + await ctx.send("Invalid input.") if isinstance(error, commands.MissingPermissions): - await ctx.send('You do not have permission to use this command.') + await ctx.send("You do not have permission to use this command.") if isinstance(error, commands.BadUnionArgument): - await ctx.send('Invalid input.') + await ctx.send("Invalid input.") except Exception as error: print(error) @@ -33,34 +31,34 @@ async def bet(self, ctx: Context, amount_to_bet: int): """ Place a bet (50/50). Enter the amount to bet. """ - user_database_check_if_user_exists_otherwise_add(ctx.author.id) + self.db.check_user(ctx.author.id) if amount_to_bet == None: - await ctx.send('You need to enter the amount to bet.', ephemeral=True) + await ctx.send("You need to enter the amount to bet.", ephemeral=True) return - amount_in_wallet = user_database_get('money', ctx.author.id) + amount_in_wallet = self.db.get_user_field("money", ctx.author.id) if amount_to_bet <= 0: - await ctx.send('You must enter a positive number greater than 0.', ephemeral=True) + await ctx.send("You must enter a positive number greater than 0.", ephemeral=True) return if amount_to_bet > amount_in_wallet: - await ctx.send('You don\'t have enough money.', ephemeral=True) + await ctx.send("You don't have enough money.", ephemeral=True) return won = random.randint(1, 2) == 1 # Update wallet. amount_result = amount_in_wallet + (amount_to_bet if won else -amount_to_bet) - user_database_set('money', amount_result, ctx.author.id) + self.db.set_user_field("money", amount_result, ctx.author.id) if won: - embed = discord.Embed(title='You won!', color=discord.Color.green()) - embed.add_field(name=f'{amount_to_bet}$ has been added to your wallet', value=f'You have {amount_result}$') + embed = discord.Embed(title="You won!", color=discord.Color.green()) + embed.add_field(name=f"{amount_to_bet}$ has been added to your wallet", value=f"You have {amount_result}$") await ctx.send(embed=embed) else: - embed = discord.Embed(title='You lost.', color=discord.Color.red()) - embed.add_field(name=f'{amount_to_bet}$ has been removed from your wallet', value=f'You have {amount_result}$') + embed = discord.Embed(title="You lost.", color=discord.Color.red()) + embed.add_field(name=f"{amount_to_bet}$ has been removed from your wallet", value=f"You have {amount_result}$") await ctx.send(embed=embed) @commands.hybrid_command(with_app_command=True) @@ -71,11 +69,11 @@ async def wallet(self, ctx: Context, user: Member = None): if user is None: user = ctx.author - user_database_check_if_user_exists_otherwise_add(user.id) + self.db.check_user(user.id) - embed = discord.Embed(title=f'{user.display_name}\'s wallet', color=discord.Color.blurple()) - embed.set_thumbnail(url='https://cdn.iconscout.com/icon/free/png-512/free-wallet-588-456730.png') - embed.add_field(name='Money', value=f'{user_database_get("money", user.id)}$') + embed = discord.Embed(title=f"{user.display_name}'s wallet", color=discord.Color.blurple()) + embed.set_thumbnail(url="https://cdn.iconscout.com/icon/free/png-512/free-wallet-588-456730.png") + embed.add_field(name="Money", value=f"{self.db.get_user_field('money', user.id)}$") await ctx.send(embed=embed) @@ -84,67 +82,68 @@ async def daily(self, ctx: Context): """ Get a small amount of money, works once per day. """ - user_database_check_if_user_exists_otherwise_add(ctx.author.id) + self.db.check_user(ctx.author.id) - last_daily_timestamp = int(user_database_get('last_daily_timestamp', ctx.author.id)) + last_daily_timestamp = int(self.db.get_user_field("last_daily_timestamp", ctx.author.id)) current_timestamp = int(time.time()) seconds_in_a_day = 86400 seconds_since_last_daily = current_timestamp - last_daily_timestamp + if seconds_since_last_daily < seconds_in_a_day: - formatted_time = datetime.fromtimestamp(seconds_in_a_day - seconds_since_last_daily).strftime('%Hh %Mm %Ss') - await ctx.send(f'You need to wait {formatted_time} before you can use this again.', ephemeral=True) + formatted_time = datetime.fromtimestamp(seconds_in_a_day - seconds_since_last_daily).strftime("%Hh %Mm %Ss") + await ctx.send(f"You need to wait `{formatted_time}` before you can use this again.", ephemeral=True) return - # Update timestamp and add money to user's wallet. - user_database_set('last_daily_timestamp', current_timestamp, ctx.author.id, commit_changes=False) - user_database_set('money', daily_amount, ctx.author.id, commit_changes=True, add_value_instead=True) + # Update timestamp and add money to user"s wallet. + self.db.set_user_field("last_daily_timestamp", current_timestamp, ctx.author.id, commit_changes=False) + self.db.set_user_field("money", conf.daily_amount, ctx.author.id, commit_changes=True, add_value_instead=True) - await ctx.send(f'{ctx.author.mention} {daily_amount}$ has been added to your wallet.') + await ctx.send(f"{ctx.author.mention} {conf.daily_amount}$ has been added to your wallet.") @commands.hybrid_command(with_app_command=True) async def give(self, ctx: Context, user: Member, amount: int): """ - Transfer money to another member. First argument is user ID. Ssecond argument is amount. + Transfer money to another member. First argument is user ID. Second argument is amount. """ - user_database_check_if_user_exists_otherwise_add(ctx.author.id) + self.db.check_user(ctx.author.id) if amount <= 0: - await ctx.send('You must enter a positive number greater than 0.', ephemeral=True) + await ctx.send("You must enter a positive number greater than 0.", ephemeral=True) return - if amount > user_database_get('money', ctx.author.id): - await ctx.send('You don\'t have enough money.', ephemeral=True) + if amount > self.db.get_user_field("money", ctx.author.id): + await ctx.send("You don't have enough money.", ephemeral=True) return if not user: - await ctx.send('User is not a valid user or not a member of this server.', ephemeral=True) + await ctx.send("User is not a valid user or not a member of this server.", ephemeral=True) return - user_database_check_if_user_exists_otherwise_add(user.id) + self.db.check_user(user.id) - user_database_set('money', -amount, ctx.author.id, commit_changes=False, add_value_instead=True) - user_database_set('money', amount, user.id, commit_changes=True, add_value_instead=True) + self.db.set_user_field("money", -amount, ctx.author.id, commit_changes=False, add_value_instead=True) + self.db.set_user_field("money", amount, user.id, commit_changes=True, add_value_instead=True) - await ctx.send(f'Transferred {amount}$ from {ctx.author.display_name} to {user.display_name}') + await ctx.send(f"Transferred {amount}$ from {ctx.author.display_name} to {user.display_name}") @commands.hybrid_command(with_app_command=True) - async def leaderboard(self, ctx: Context, entries: int = 10): + async def leaderboard(self, ctx: Context, max_entries: int = 10): """ Show the members with the most money. """ - # Poor man's clamp. - entries = max(1, min(entries, 50)) + # Poor man"s clamp. + max_entries = max(1, min(max_entries, 50)) - query = user_database.execute(f'SELECT id, money FROM users ORDER BY money DESC LIMIT ?', [entries]) + entries = self.db.get_money_leaderboard(max_entries) - member_list = '' + member_list = "" - for index, entry in enumerate(query.fetchall()): + for index, entry in enumerate(entries): user_id = entry[0] user_money = entry[1] - member_list += f'{index + 1}. {self.bot.get_user(user_id).mention} {user_money}$\n' + member_list += f"{index + 1}. {self.bot.get_user(user_id).mention} {user_money}$\n" - embed = discord.Embed(title='Leaderboard', color=discord.Color.blurple()) - embed.add_field(name=f'Showing top {entries} members', value=member_list) + embed = discord.Embed(title="Leaderboard", color=discord.Color.blurple()) + embed.add_field(name=f"Showing top {max_entries} members", value=member_list) await ctx.send(embed=embed) diff --git a/src/config.py b/src/config.py index 17f8f74..f5a84af 100644 --- a/src/config.py +++ b/src/config.py @@ -52,3 +52,7 @@ help_channel : 'Done', # help 1055500115432972318 : 'Done' # code-review } + +user_db_path = "users.db" + +daily_amount = 10 diff --git a/src/init.sql b/src/init.sql new file mode 100644 index 0000000..c6b06a1 --- /dev/null +++ b/src/init.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS users( + id INTEGER NOT NULL PRIMARY KEY, + money INTEGER NOT NULL, + last_daily_timestamp INTEGER NOT NULL +); diff --git a/src/util/db.py b/src/util/db.py new file mode 100644 index 0000000..072cea6 --- /dev/null +++ b/src/util/db.py @@ -0,0 +1,38 @@ +import sqlite3 +from pathlib import Path + +class Database: + def __init__(self, path: Path): + self.connection = sqlite3.connect(path) + self.cursor = self.connection.cursor() + + self.cursor.executescript((Path(__file__).parent.parent / "init.sql").read_text()) + self.connection.commit() + + def get_user_field(self, field_name, user_id): + cursor = self.cursor.execute(f"SELECT {field_name} FROM users WHERE id = ?", [user_id]) + return cursor.fetchone()[0] + + def get_money_leaderboard(self, max_entries): + cursor = self.cursor.execute(f"SELECT id, money FROM users ORDER BY money DESC LIMIT ?", [max_entries]) + return cursor.fetchall() + + def set_user_field(self, field_name, value, user_id, commit_changes = True, add_value_instead = False): + self.cursor.execute(f"UPDATE users SET {field_name} = {(field_name + ' +') if add_value_instead else ''} ? WHERE id = ?", [value, user_id]) + if commit_changes: + self.connection.commit() + + def check_user(self, user_id): + """ + NOTE: This function only checks if a user ID exists in the database, not if the user ID belongs to a valid server member. + """ + # Query number of times user id is found which should be 0 or 1. + cursor = self.cursor.execute("SELECT COUNT(*) FROM users WHERE id = ?", [user_id]) + count = cursor.fetchone()[0] + + # If no user ID was found in database, add user. + if count == 0: + self.cursor.execute("INSERT INTO users VALUES (?, 0, 0)", [user_id]) + self.connection.commit() + elif count > 1: + raise Exception(f"Found multiple copies of user ID ({user_id}) in database.") diff --git a/src/util/user_database.py b/src/util/user_database.py deleted file mode 100644 index ff7531a..0000000 --- a/src/util/user_database.py +++ /dev/null @@ -1,31 +0,0 @@ -import sqlite3 - -user_database_connection = sqlite3.connect('users.db') -user_database = user_database_connection.cursor() - -user_database.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER, money INTEGER, last_daily_timestamp INTEGER)') -user_database_connection.commit() - -def user_database_get(field_name, user_id): - query = user_database.execute(f'SELECT {field_name} FROM users WHERE id = ?', [user_id]) - return query.fetchone()[0] - -def user_database_set(field_name, value, user_id, commit_changes = True, add_value_instead = False): - user_database.execute(f'UPDATE users SET {field_name} = {(field_name + " +") if add_value_instead else ""} ? WHERE id = ?', [value, user_id]) - if commit_changes: - user_database_connection.commit() - -def user_database_check_if_user_exists_otherwise_add(user_id): - """ - NOTE: This function only checks if a user ID exists in the database, not if the user ID belongs to a valid server member. - """ - # Query number of times user id is found which should be 0 or 1. - query = user_database.execute('SELECT COUNT(*) FROM users WHERE id = ?', [user_id]) - count = query.fetchone()[0] - - # If no user ID was found in database, add user. - if count == 0: - user_database.execute('INSERT INTO users VALUES (?, 0, 0)', [user_id]) - user_database_connection.commit() - elif count > 1: - raise Exception(f'Found multiple copies of user ID ({user_id}) in database.') \ No newline at end of file From 43aa5de6d6d1840c4395f21130628ce0201de971 Mon Sep 17 00:00:00 2001 From: Comlud Date: Mon, 25 Dec 2023 15:38:33 +0100 Subject: [PATCH 3/8] Fixed /daily and sticker in embed Still need to update the sticker id in config.py after Che uploads the sticker. --- src/__main__.py | 2 +- src/cogs/gamble.py | 13 ++++++++----- src/config.py | 4 +++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 5d3b42f..e9e4d9a 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -15,7 +15,7 @@ def prefix(bot, message): @bot.event async def on_ready(): - bot.user_db = Database(conf.user_db_path) + bot.db = Database(conf.database_path) bot.user_cogs = [ # "src.cogs.verona", diff --git a/src/cogs/gamble.py b/src/cogs/gamble.py index 25419ec..638ce1c 100644 --- a/src/cogs/gamble.py +++ b/src/cogs/gamble.py @@ -1,18 +1,18 @@ import random import time +import datetime from discord.ext import commands import discord from discord.ext.commands import Context from discord import Member -from datetime import datetime from src import config as conf class Gamble(commands.Cog, name="Gamble"): def __init__(self, bot): self.bot = bot - self.db = bot.user_db + self.db = bot.db @commands.Cog.listener() async def on_command_error(self, ctx: Context, error): @@ -71,8 +71,10 @@ async def wallet(self, ctx: Context, user: Member = None): self.db.check_user(user.id) + sticker_url = f"https://cdn.discordapp.com/stickers/{conf.wallet_sticker_id}.png" + embed = discord.Embed(title=f"{user.display_name}'s wallet", color=discord.Color.blurple()) - embed.set_thumbnail(url="https://cdn.iconscout.com/icon/free/png-512/free-wallet-588-456730.png") + embed.set_thumbnail(url=sticker_url) embed.add_field(name="Money", value=f"{self.db.get_user_field('money', user.id)}$") await ctx.send(embed=embed) @@ -90,8 +92,9 @@ async def daily(self, ctx: Context): seconds_since_last_daily = current_timestamp - last_daily_timestamp if seconds_since_last_daily < seconds_in_a_day: - formatted_time = datetime.fromtimestamp(seconds_in_a_day - seconds_since_last_daily).strftime("%Hh %Mm %Ss") - await ctx.send(f"You need to wait `{formatted_time}` before you can use this again.", ephemeral=True) + seconds_to_wait = seconds_in_a_day - seconds_since_last_daily + + await ctx.send(f"You need to wait `{str(datetime.timedelta(seconds=seconds_to_wait))}` before you can use this again.", ephemeral=True) return # Update timestamp and add money to user"s wallet. diff --git a/src/config.py b/src/config.py index f5a84af..2d1ec1e 100644 --- a/src/config.py +++ b/src/config.py @@ -53,6 +53,8 @@ 1055500115432972318 : 'Done' # code-review } -user_db_path = "users.db" +database_path = "database.db" daily_amount = 10 + +wallet_sticker_id = 1188841359927427092 From 8c39d3abd6ab382a157d9b4f88de47333a5dbfd6 Mon Sep 17 00:00:00 2001 From: Comlud Date: Sat, 20 Jan 2024 13:36:55 +0100 Subject: [PATCH 4/8] Fixed all of Che's requests. --- src/cogs/gamble.py | 12 ++++++------ src/config.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cogs/gamble.py b/src/cogs/gamble.py index 638ce1c..107e3ca 100644 --- a/src/cogs/gamble.py +++ b/src/cogs/gamble.py @@ -54,11 +54,11 @@ async def bet(self, ctx: Context, amount_to_bet: int): if won: embed = discord.Embed(title="You won!", color=discord.Color.green()) - embed.add_field(name=f"{amount_to_bet}$ has been added to your wallet", value=f"You have {amount_result}$") + embed.add_field(name=f"${amount_to_bet} has been added to your wallet", value=f"You have ${amount_result}") await ctx.send(embed=embed) else: embed = discord.Embed(title="You lost.", color=discord.Color.red()) - embed.add_field(name=f"{amount_to_bet}$ has been removed from your wallet", value=f"You have {amount_result}$") + embed.add_field(name=f"${amount_to_bet} has been removed from your wallet", value=f"You have ${amount_result}") await ctx.send(embed=embed) @commands.hybrid_command(with_app_command=True) @@ -75,7 +75,7 @@ async def wallet(self, ctx: Context, user: Member = None): embed = discord.Embed(title=f"{user.display_name}'s wallet", color=discord.Color.blurple()) embed.set_thumbnail(url=sticker_url) - embed.add_field(name="Money", value=f"{self.db.get_user_field('money', user.id)}$") + embed.add_field(name="Money", value=f"${self.db.get_user_field('money', user.id)}") await ctx.send(embed=embed) @@ -101,7 +101,7 @@ async def daily(self, ctx: Context): self.db.set_user_field("last_daily_timestamp", current_timestamp, ctx.author.id, commit_changes=False) self.db.set_user_field("money", conf.daily_amount, ctx.author.id, commit_changes=True, add_value_instead=True) - await ctx.send(f"{ctx.author.mention} {conf.daily_amount}$ has been added to your wallet.") + await ctx.send(f"{ctx.author.mention} ${conf.daily_amount} has been added to your wallet.") @commands.hybrid_command(with_app_command=True) async def give(self, ctx: Context, user: Member, amount: int): @@ -126,7 +126,7 @@ async def give(self, ctx: Context, user: Member, amount: int): self.db.set_user_field("money", -amount, ctx.author.id, commit_changes=False, add_value_instead=True) self.db.set_user_field("money", amount, user.id, commit_changes=True, add_value_instead=True) - await ctx.send(f"Transferred {amount}$ from {ctx.author.display_name} to {user.display_name}") + await ctx.send(f"Transferred ${amount} from {ctx.author.display_name} to {user.display_name}") @commands.hybrid_command(with_app_command=True) async def leaderboard(self, ctx: Context, max_entries: int = 10): @@ -143,7 +143,7 @@ async def leaderboard(self, ctx: Context, max_entries: int = 10): for index, entry in enumerate(entries): user_id = entry[0] user_money = entry[1] - member_list += f"{index + 1}. {self.bot.get_user(user_id).mention} {user_money}$\n" + member_list += f"{index + 1}. {self.bot.get_user(user_id).mention} ${user_money}\n" embed = discord.Embed(title="Leaderboard", color=discord.Color.blurple()) embed.add_field(name=f"Showing top {max_entries} members", value=member_list) diff --git a/src/config.py b/src/config.py index 2d1ec1e..bf83feb 100644 --- a/src/config.py +++ b/src/config.py @@ -57,4 +57,4 @@ daily_amount = 10 -wallet_sticker_id = 1188841359927427092 +wallet_sticker_id = 1193982589556490440 From 4c92d8c7b09e941c85a928539b885b2942df3905 Mon Sep 17 00:00:00 2001 From: Comlud Date: Sun, 19 May 2024 09:43:10 +0200 Subject: [PATCH 5/8] Moved database. --- src/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.py b/src/config.py index bf83feb..da1c22e 100644 --- a/src/config.py +++ b/src/config.py @@ -53,7 +53,7 @@ 1055500115432972318 : 'Done' # code-review } -database_path = "database.db" +database_path = "persistent/database.db" daily_amount = 10 From 473fa23fed5f0f5d2c7b9b67e4939e03d07d6d18 Mon Sep 17 00:00:00 2001 From: vex Date: Sun, 19 May 2024 10:49:47 +0300 Subject: [PATCH 6/8] persistent volume --- Dockerfile | 1 + docker-compose.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Dockerfile b/Dockerfile index 07727ba..a93db84 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ RUN apt update -y \ RUN adduser --disabled-password --gecos "" bettercbot USER bettercbot WORKDIR /home/bettercbot +RUN mkdir persistent ENV PATH="/home/bettercbot/.local/bin:$PATH" COPY --chown=bettercbot:bettercbot src/cppref src/cppref diff --git a/docker-compose.yml b/docker-compose.yml index e32ca60..e49c5ec 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,3 +3,7 @@ services: bot: build: . restart: unless-stopped + volumes: + - bot-persistent:/home/bettercbot/database +volumes: + bot-persistent: From d0357a12f07eb4b8426252161db47569b48f88db Mon Sep 17 00:00:00 2001 From: vex Date: Sun, 19 May 2024 10:54:45 +0300 Subject: [PATCH 7/8] persistent volume --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e49c5ec..51a1a20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,6 @@ services: build: . restart: unless-stopped volumes: - - bot-persistent:/home/bettercbot/database + - bot-persistent:/home/bettercbot/persistent volumes: bot-persistent: From 96e9d40c871681755a0307d38fb746e53cbfe634 Mon Sep 17 00:00:00 2001 From: Comlud Date: Sun, 19 May 2024 13:11:00 +0200 Subject: [PATCH 8/8] Moved gamble specific functions from db.py --- src/cogs/gamble.py | 65 +++++++++++++++++++++++++++++++++++----------- src/util/db.py | 30 +-------------------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/cogs/gamble.py b/src/cogs/gamble.py index 107e3ca..cda5abe 100644 --- a/src/cogs/gamble.py +++ b/src/cogs/gamble.py @@ -8,11 +8,46 @@ from discord import Member from src import config as conf +from src.util.db import Database + +class Users: + """ Helper class for managing the `users` table in the database. """ + def __init__(self, db: Database): + self.db = db + + def get_field(self, field_name: str, user_id: int): + cursor = self.db.cursor.execute(f"SELECT {field_name} FROM users WHERE id = ?", [user_id]) + return cursor.fetchone()[0] + + def get_leaderboard(self, max_entries: int): + cursor = self.db.cursor.execute(f"SELECT id, money FROM users ORDER BY money DESC LIMIT ?", [max_entries]) + return cursor.fetchall() + + def set_field(self, field_name: str, value, user_id: int, commit_changes: bool = True, add_value_instead: bool = False): + self.db.cursor.execute(f"UPDATE users SET {field_name} = {(field_name + ' +') if add_value_instead else ''} ? WHERE id = ?", [value, user_id]) + if commit_changes: + self.db.connection.commit() + + def check_user(self, user_id: int): + """ + NOTE: This function only checks if a user ID exists in the database, not if the user ID belongs to a valid server member. + """ + # Query number of times user id is found which should be 0 or 1. + cursor = self.db.cursor.execute("SELECT COUNT(*) FROM users WHERE id = ?", [user_id]) + count = cursor.fetchone()[0] + + # If no user ID was found in database, add user. + if count == 0: + self.db.cursor.execute("INSERT INTO users VALUES (?, 0, 0)", [user_id]) + self.db.connection.commit() + elif count > 1: + raise Exception(f"Found multiple copies of user ID ({user_id}) in database.") class Gamble(commands.Cog, name="Gamble"): def __init__(self, bot): self.bot = bot self.db = bot.db + self.users = Users(self.db) @commands.Cog.listener() async def on_command_error(self, ctx: Context, error): @@ -31,13 +66,13 @@ async def bet(self, ctx: Context, amount_to_bet: int): """ Place a bet (50/50). Enter the amount to bet. """ - self.db.check_user(ctx.author.id) + self.users.check_user(ctx.author.id) if amount_to_bet == None: await ctx.send("You need to enter the amount to bet.", ephemeral=True) return - amount_in_wallet = self.db.get_user_field("money", ctx.author.id) + amount_in_wallet = self.users.get_field("money", ctx.author.id) if amount_to_bet <= 0: await ctx.send("You must enter a positive number greater than 0.", ephemeral=True) @@ -50,7 +85,7 @@ async def bet(self, ctx: Context, amount_to_bet: int): # Update wallet. amount_result = amount_in_wallet + (amount_to_bet if won else -amount_to_bet) - self.db.set_user_field("money", amount_result, ctx.author.id) + self.users.set_field("money", amount_result, ctx.author.id) if won: embed = discord.Embed(title="You won!", color=discord.Color.green()) @@ -69,13 +104,13 @@ async def wallet(self, ctx: Context, user: Member = None): if user is None: user = ctx.author - self.db.check_user(user.id) + self.users.check_user(user.id) sticker_url = f"https://cdn.discordapp.com/stickers/{conf.wallet_sticker_id}.png" embed = discord.Embed(title=f"{user.display_name}'s wallet", color=discord.Color.blurple()) embed.set_thumbnail(url=sticker_url) - embed.add_field(name="Money", value=f"${self.db.get_user_field('money', user.id)}") + embed.add_field(name="Money", value=f"${self.users.get_field('money', user.id)}") await ctx.send(embed=embed) @@ -84,9 +119,9 @@ async def daily(self, ctx: Context): """ Get a small amount of money, works once per day. """ - self.db.check_user(ctx.author.id) + self.users.check_user(ctx.author.id) - last_daily_timestamp = int(self.db.get_user_field("last_daily_timestamp", ctx.author.id)) + last_daily_timestamp = int(self.users.get_field("last_daily_timestamp", ctx.author.id)) current_timestamp = int(time.time()) seconds_in_a_day = 86400 seconds_since_last_daily = current_timestamp - last_daily_timestamp @@ -98,8 +133,8 @@ async def daily(self, ctx: Context): return # Update timestamp and add money to user"s wallet. - self.db.set_user_field("last_daily_timestamp", current_timestamp, ctx.author.id, commit_changes=False) - self.db.set_user_field("money", conf.daily_amount, ctx.author.id, commit_changes=True, add_value_instead=True) + self.users.set_field("last_daily_timestamp", current_timestamp, ctx.author.id, commit_changes=False) + self.users.set_field("money", conf.daily_amount, ctx.author.id, commit_changes=True, add_value_instead=True) await ctx.send(f"{ctx.author.mention} ${conf.daily_amount} has been added to your wallet.") @@ -108,12 +143,12 @@ async def give(self, ctx: Context, user: Member, amount: int): """ Transfer money to another member. First argument is user ID. Second argument is amount. """ - self.db.check_user(ctx.author.id) + self.users.check_user(ctx.author.id) if amount <= 0: await ctx.send("You must enter a positive number greater than 0.", ephemeral=True) return - if amount > self.db.get_user_field("money", ctx.author.id): + if amount > self.users.get_field("money", ctx.author.id): await ctx.send("You don't have enough money.", ephemeral=True) return @@ -121,10 +156,10 @@ async def give(self, ctx: Context, user: Member, amount: int): await ctx.send("User is not a valid user or not a member of this server.", ephemeral=True) return - self.db.check_user(user.id) + self.users.check_user(user.id) - self.db.set_user_field("money", -amount, ctx.author.id, commit_changes=False, add_value_instead=True) - self.db.set_user_field("money", amount, user.id, commit_changes=True, add_value_instead=True) + self.users.set_field("money", -amount, ctx.author.id, commit_changes=False, add_value_instead=True) + self.users.set_field("money", amount, user.id, commit_changes=True, add_value_instead=True) await ctx.send(f"Transferred ${amount} from {ctx.author.display_name} to {user.display_name}") @@ -136,7 +171,7 @@ async def leaderboard(self, ctx: Context, max_entries: int = 10): # Poor man"s clamp. max_entries = max(1, min(max_entries, 50)) - entries = self.db.get_money_leaderboard(max_entries) + entries = self.users.get_leaderboard(max_entries) member_list = "" diff --git a/src/util/db.py b/src/util/db.py index 072cea6..c2a0c57 100644 --- a/src/util/db.py +++ b/src/util/db.py @@ -7,32 +7,4 @@ def __init__(self, path: Path): self.cursor = self.connection.cursor() self.cursor.executescript((Path(__file__).parent.parent / "init.sql").read_text()) - self.connection.commit() - - def get_user_field(self, field_name, user_id): - cursor = self.cursor.execute(f"SELECT {field_name} FROM users WHERE id = ?", [user_id]) - return cursor.fetchone()[0] - - def get_money_leaderboard(self, max_entries): - cursor = self.cursor.execute(f"SELECT id, money FROM users ORDER BY money DESC LIMIT ?", [max_entries]) - return cursor.fetchall() - - def set_user_field(self, field_name, value, user_id, commit_changes = True, add_value_instead = False): - self.cursor.execute(f"UPDATE users SET {field_name} = {(field_name + ' +') if add_value_instead else ''} ? WHERE id = ?", [value, user_id]) - if commit_changes: - self.connection.commit() - - def check_user(self, user_id): - """ - NOTE: This function only checks if a user ID exists in the database, not if the user ID belongs to a valid server member. - """ - # Query number of times user id is found which should be 0 or 1. - cursor = self.cursor.execute("SELECT COUNT(*) FROM users WHERE id = ?", [user_id]) - count = cursor.fetchone()[0] - - # If no user ID was found in database, add user. - if count == 0: - self.cursor.execute("INSERT INTO users VALUES (?, 0, 0)", [user_id]) - self.connection.commit() - elif count > 1: - raise Exception(f"Found multiple copies of user ID ({user_id}) in database.") + self.connection.commit() \ No newline at end of file