Fix SQL lockups, get commands working, remove DB and availcommands and .env

This commit is contained in:
Will Bradley 2024-04-10 15:57:28 -07:00
parent f50221c672
commit 05074d33be
Signed by: will
GPG Key ID: 1159B930701263F3
6 changed files with 169 additions and 48 deletions

6
.env
View File

@ -1,6 +0,0 @@
##EXAMPLE .ENV FILE
BOT_TOKEN = "INPUT DISCORD API KEY HERE"
BOT_CHANNEL_ID = INPUT CHANNEL ID FOR COMMANDS
WELCOME_CHANNEL_ID = INPUT CHANNEL ID FOR YOUR WELCOME MESSAGE MAINTENANCE
GUILD_ID = INPUT GUILD ID FOR YOUR DISCORD SERVER

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.env *.env
/.venv /.venv
member_data.db member_data.db
discord.log discord.log
SparkBot.log

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# SparkBot
A Discord bot for Spark Studio Salem
## Prerequisites
- Go to https://discord.com/developers/applications and make an application
- Go to the Bot page.
- Copy `env.dist` to `.env` and add the Bot Token to this file.
- Choose what channels you want the bot to operate in on your server and add their IDs to the file as well.
## Installation
Requires Python 3.
- Run `pip install -r requirements.txt`
## Running
Run `python3 main.py`
## Usage
### Available Commands
```
/help : to view all commands
/nick : to view current nickname
/setnick : to change nickname
/reinit : to re-initialize a user in the database (i.e. if they joined when the bot wasn't listening)
```
## Database
Initialization of the structure is automatically handled inside `main.py` and
creates the SQLITE3 file `member_data.db`.

6
env.dist Normal file
View File

@ -0,0 +1,6 @@
##EXAMPLE .ENV FILE
BOT_TOKEN = ""INPUT DISCORD API KEY HERE"
BOT_CHANNEL_ID = INPUT CHANNEL ID FOR COMMANDS
WELCOME_CHANNEL_ID = INPUT WELCOME CHANNEL ID HERE
GUILD_ID = INPUT GUILD ID HERE

165
main.py
View File

@ -7,7 +7,7 @@ import sqlite3
import logging import logging
from datetime import datetime, timezone from datetime import datetime, timezone
from discord import ui, Interaction from discord import ui, Interaction
import random
async def welcome_message(): async def welcome_message():
# Find the #welcome channel # Find the #welcome channel
@ -37,26 +37,44 @@ async def welcome_message():
async def update_nickname(member, firstname, lastname): #update server nickname from DB async def update_nickname(member, firstname, lastname): #update server nickname from DB
nickname = f"{firstname} {lastname}" nickname = f"{firstname} {lastname}"
c.execute("UPDATE members SET nickname = ?, firstname = ?, lastname = ? WHERE user_id = ?", (nickname, firstname, lastname, member.id)) with sqlite3.connect('member_data.db') as conn:
conn.commit() c = conn.cursor()
print(f'Updated DB nickname for: {member}, {firstname}, {lastname}, {nickname}') c.execute("UPDATE members SET nickname = ?, firstname = ?, lastname = ? WHERE user_id = ?", (nickname, firstname, lastname, member.id))
conn.commit()
print(f'Updated DB nickname for: {member}, {firstname}, {lastname}, {nickname}')
await member.edit(nick=nickname) await member.edit(nick=nickname)
async def remove_user(user): #Remove user from DB and delete server nickname async def remove_user(user): #Remove user from DB and delete server nickname
c.execute("DELETE FROM members WHERE user_id = ?", (user.id,)) with sqlite3.connect('member_data.db') as conn:
conn.commit() c = conn.cursor()
c.execute("DELETE FROM members WHERE user_id = ?", (user.id,))
conn.commit()
if user: if user:
await user.edit(nick=None) await user.edit(nick=None)
#TODO demote user role #TODO demote user role
async def update_onboard(member): #increase onboarding status by 1 async def update_onboard(member): #increase onboarding status by 1
print(f'Updating onboarding for: {member.display_name}') logging.info(f'Updating onboarding for: {member.display_name} {member.id}')
c.execute("SELECT onboarding_status FROM members WHERE user_id = ?", (member.id,))
status = c.fetchone() # Connect to the database using a context manager
status += 1 with sqlite3.connect('member_data.db') as conn:
c.execute("UPDATE members SET onboarding_status = ? WHERE user_id = ?", c = conn.cursor()
(status, member.id))
conn.commit() c.execute("SELECT onboarding_status FROM members WHERE user_id = ?", (member.id,))
row = c.fetchone()
if row is None:
logging.error("No matching user found in the database.")
return
status = row[0]
status += 1
c.execute("UPDATE members SET onboarding_status = ? WHERE user_id = ?",
(status, member.id))
conn.commit()
logging.warning(f'Updated onboarding for {member.display_name}: {status}')
async def add_member_to_role(member, role_name): async def add_member_to_role(member, role_name):
print(f"Adding {role_name} role to {member.display_name}") print(f"Adding {role_name} role to {member.display_name}")
@ -77,25 +95,26 @@ logging.basicConfig(filename='SparkBot.log', level=logging.INFO)
intents = discord.Intents.all() intents = discord.Intents.all()
# Connect to SQLite database # Connect to SQLite database
conn = sqlite3.connect('member_data.db') with sqlite3.connect('member_data.db') as conn:
c = conn.cursor() c = conn.cursor()
# Create table with fields if it doesn't exist already # Create table with fields if it doesn't exist already
c.execute('''CREATE TABLE IF NOT EXISTS members ( c.execute('''CREATE TABLE IF NOT EXISTS members (
user_id INTEGER PRIMARY KEY, user_id INTEGER PRIMARY KEY,
username TEXT, nickname TEXT, username TEXT, nickname TEXT,
firstname TEXT, lastname TEXT, firstname TEXT, lastname TEXT,
join_datetime TEXT, join_datetime TEXT,
onboarding_status INTEGER, onboarding_status INTEGER,
last_change_datetime TEXT last_change_datetime TEXT
)''') )''')
conn.commit()
conn.commit()
class PersistentViewBot(commands.Bot): class PersistentViewBot(commands.Bot):
def __init__(self): def __init__(self):
intents = discord.Intents().all() intents = discord.Intents().all()
super().__init__(command_prefix=commands.when_mentioned_or("."), intents=intents) super().__init__(command_prefix=commands.when_mentioned_or("/"), intents=intents)
async def setup_hook(self) -> None: async def setup_hook(self) -> None:
self.add_view(OnboardButtons()) self.add_view(OnboardButtons())
#self.add_view(OnboardButtons()) #Add More views with more add_view commands. #self.add_view(OnboardButtons()) #Add More views with more add_view commands.
@ -151,26 +170,92 @@ async def on_ready():
except Exception as e: except Exception as e:
print(e) print(e)
print("Members in the DB:")
with sqlite3.connect('member_data.db') as conn:
c = conn.cursor()
c.execute("SELECT user_id, username, nickname FROM members")
for row in c.fetchall():
print(f' ID: {row[0]} User: {row[1]} Nick: {row[2]}')
print("Ready.")
@client.command(name='reinit')
async def cmd_reinit(ctx):
"""Re-initialize a user in the database (i.e. if the bot wasn't listening when they joined)"""
await on_member_join(ctx.author)
await ctx.send("Reinitialized!")
@client.command(name='nick')
async def cmd_nick(ctx):
"""View current nickname"""
await ctx.send(f'You are {ctx.author.nick}')
@client.command(name='setnick')
async def cmd_setnick(ctx, arg1, arg2):
"""Change nickname (use two words separated by a space)"""
await update_nickname(ctx.author, arg1, arg2)
await ctx.send(f'You are now {ctx.author.nick}')
@client.command(name='99')
async def cmd_nine_nine(ctx):
brooklyn_99_quotes = [
'I\'m the human form of the 💯 emoji.',
'Bingpot!',
(
'Cool. Cool cool cool cool cool cool cool, '
'no doubt no doubt no doubt no doubt.'
),
]
response = random.choice(brooklyn_99_quotes)
await ctx.send(response)
# @client.event
# async def on_message(message):
# if message.author == client.user:
# return
# brooklyn_99_quotes = [
# 'I\'m the human form of the 💯 emoji.',
# 'Bingpot!',
# (
# 'Cool. Cool cool cool cool cool cool cool, '
# 'no doubt no doubt no doubt no doubt.'
# ),
# ]
# if message.content == '/99':
# response = random.choice(brooklyn_99_quotes)
# await message.channel.send(response)
@client.event @client.event
async def on_member_join(member): async def on_member_join(member):
await welcome_message() await welcome_message()
# Check if member already exists in the database
c.execute("SELECT * FROM members WHERE user_id = ?", (member.id,))
existing_member = c.fetchone()
if not existing_member: # If it's the member's first time joining with sqlite3.connect('member_data.db') as conn:
# Add new member to the database c = conn.cursor()
c.execute(
"INSERT OR REPLACE INTO members (user_id, username, join_datetime, onboarding_status, last_change_datetime) VALUES (?, ?, ?, ?, ?)",
(member.id, member.name, member.joined_at.isoformat(), 0, datetime.now(timezone.utc).isoformat()))
conn.commit()
# Update member nickname # Check if member already exists in the database
await member.edit(nick=c.execute("SELECT nickname FROM members WHERE user_id = ?", (member.id,)).fetchone()[0]) c.execute("SELECT * FROM members WHERE user_id = ?", (member.id,))
# Log member join existing_member = c.fetchone()
logging.info(f'Member {member.name} joined the server.')
if not existing_member: # If it's the member's first time joining
# Add new member to the database
c.execute(
"INSERT OR REPLACE INTO members (user_id, username, join_datetime, onboarding_status, last_change_datetime) VALUES (?, ?, ?, ?, ?)",
(member.id, member.name, member.joined_at.isoformat(), 0, datetime.now(timezone.utc).isoformat()))
conn.commit()
# Update member nickname
await member.edit(nick=c.execute("SELECT nickname FROM members WHERE user_id = ?", (member.id,)).fetchone()[0])
# Log member join
logging.warning(f'Member {member.name} joined the server.')
else:
logging.info(f'Member {member.name} rejoined the server.')
@client.tree.command(name="remove", description="Remove user from database, and remove user's nickname") @client.tree.command(name="remove", description="Remove user from database, and remove user's nickname")
@app_commands.describe(member="The member you want to remove") @app_commands.describe(member="The member you want to remove")
@ -181,7 +266,7 @@ async def remove(interaction: discord.Integration, member: discord.Member):
@client.event @client.event
async def on_member_remove(member): async def on_member_remove(member):
# Log member leave # Log member leave
logging.info(f'Member {member.name} left the server.') logging.warning(f'Member {member.name} left the server.')
# Load bot token and welcome channel id from .env file # Load bot token and welcome channel id from .env file

View File

@ -10,6 +10,5 @@ discord==2.3.2
discord.py==2.3.2 discord.py==2.3.2
frozenlist==1.4.1 frozenlist==1.4.1
idna==3.6 idna==3.6
logging==0.4.9.6
multidict==6.0.5 multidict==6.0.5
yarl==1.9.4 yarl==1.9.4