Turn SparkBot into MineBot
This commit is contained in:
parent
f44468e4b6
commit
9bf136abf5
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,5 +1,4 @@
|
||||||
*.env
|
*.env
|
||||||
/.venv
|
/.venv
|
||||||
member_data.db
|
bot_data.db
|
||||||
discord.log
|
bot.log
|
||||||
SparkBot.log
|
|
Binary file not shown.
27
README.md
27
README.md
|
@ -1,6 +1,8 @@
|
||||||
# SparkBot
|
# MineBot
|
||||||
|
|
||||||
A Discord bot for Spark Studio Salem
|
A Discord bot for managing your Minecraft server via [Minecraft Minder](https://git.zyphon.com/will/minecraft-minder)
|
||||||
|
|
||||||
|
Forked from [SparkBot](https://github.com/jkkicks/SparkBot)
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
@ -21,16 +23,25 @@ Run `python3 main.py`
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Available Commands
|
### Command Tree
|
||||||
|
|
||||||
```
|
```
|
||||||
/help : to view all commands
|
/addserver - Add a Minecraft server to the bot (global)
|
||||||
/nick : to view current nickname
|
/adduser - Add a user to a Minecraft server (global)
|
||||||
/setnick : to change nickname
|
/removeuser - Remove a user from a Minecraft server
|
||||||
/reinit : to re-initialize a user in the database (i.e. if they joined when the bot wasn't listening)
|
/listservers - List the Minecraft servers you have access to
|
||||||
|
/status - Get the status of the first Minecraft server you have acces to
|
||||||
|
/start - Start the first Minecraft server you have acces to
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Hidden commands
|
||||||
|
```
|
||||||
|
/99 - Brooklyn 99 Quotes
|
||||||
|
/shutdown - Kill the bot (global)
|
||||||
|
/sync - Sync the slash-command tree with Discord
|
||||||
```
|
```
|
||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
Initialization of the structure is automatically handled inside `main.py` and
|
Initialization of the structure is automatically handled inside `main.py` and
|
||||||
creates the SQLITE3 file `member_data.db`.
|
creates the SQLITE3 file `bot_data.db`.
|
3
env.dist
3
env.dist
|
@ -1,6 +1,3 @@
|
||||||
##EXAMPLE .ENV FILE
|
##EXAMPLE .ENV FILE
|
||||||
|
|
||||||
BOT_TOKEN = ""INPUT DISCORD API KEY HERE"
|
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
|
|
||||||
|
|
475
main.py
475
main.py
|
@ -9,197 +9,250 @@ from datetime import datetime, timezone
|
||||||
from discord import ui, Interaction
|
from discord import ui, Interaction
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
async def welcome_message():
|
## Defines ##
|
||||||
# Find the #welcome channel
|
|
||||||
welcome_channel_id = int(os.getenv('WELCOME_CHANNEL_ID'))
|
|
||||||
welcome_channel = discord.utils.get(client.get_all_channels(), id=welcome_channel_id)
|
|
||||||
|
|
||||||
# Check if welcome message has already been sent in the channel
|
# Load environment variables from .env file
|
||||||
async for message in welcome_channel.history(limit=100):
|
|
||||||
if message.author == client.user and message.embeds:
|
|
||||||
print(f'Welcome message found. Message ID: {message.id}')
|
|
||||||
return # If the welcome message is found, exit the function
|
|
||||||
|
|
||||||
# Send welcome message in the #welcome channel
|
|
||||||
print(f'No welcome message found, creating one now')
|
|
||||||
view = discord.ui.View()
|
|
||||||
button = discord.ui.Button(label="Complete Onboarding")
|
|
||||||
view.add_item(button)
|
|
||||||
embed = discord.Embed(title="Welcome to the Server!", description="Here's how to get started:")
|
|
||||||
# embed.set_thumbnail(url=ctx.guild.icon)
|
|
||||||
embed.add_field(name="Step 1:",
|
|
||||||
value="Read the server rules in [#rules](https://discord.com/channels/1207801896656568480/1207802982574596137) channel.")
|
|
||||||
embed.add_field(name="Step 2:",
|
|
||||||
value="Check out some cool posts over in [#projects](https://discord.com/channels/1207801896656568480/1207807674075320390).")
|
|
||||||
embed.add_field(name="Step 3:", value="Complete Onboarding procedure to unlock the rest of the server.")
|
|
||||||
embed.set_footer(text="Enjoy your stay!")
|
|
||||||
await welcome_channel.send(embed=embed, view=OnboardButtons())
|
|
||||||
|
|
||||||
async def update_nickname(member, firstname, lastname): #update server nickname from DB
|
|
||||||
nickname = f"{firstname} {lastname}"
|
|
||||||
with sqlite3.connect('member_data.db') as conn:
|
|
||||||
c = conn.cursor()
|
|
||||||
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)
|
|
||||||
|
|
||||||
async def remove_user(user): #Remove user from DB and delete server nickname
|
|
||||||
with sqlite3.connect('member_data.db') as conn:
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute("DELETE FROM members WHERE user_id = ?", (user.id,))
|
|
||||||
conn.commit()
|
|
||||||
if user:
|
|
||||||
await user.edit(nick=None)
|
|
||||||
#TODO demote user role
|
|
||||||
|
|
||||||
async def update_onboard(member): #increase onboarding status by 1
|
|
||||||
logging.info(f'Updating onboarding for: {member.display_name} {member.id}')
|
|
||||||
|
|
||||||
# Connect to the database using a context manager
|
|
||||||
with sqlite3.connect('member_data.db') as conn:
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
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):
|
|
||||||
print(f"Adding {role_name} role to {member.display_name}")
|
|
||||||
role = discord.utils.get(member.guild.roles, name=role_name) # Get role from guild
|
|
||||||
if role:
|
|
||||||
await member.add_roles(role)
|
|
||||||
print(f"Added role '{role_name}' to member '{member.display_name}'")
|
|
||||||
else:
|
|
||||||
print(f"Role '{role_name}' not found in server '{member.guild.name}'")
|
|
||||||
|
|
||||||
# Load environment variables
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
# Load bot token and welcome channel id from environment variables
|
||||||
|
TOKEN = os.getenv('BOT_TOKEN')
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
logging.basicConfig(filename='SparkBot.log', level=logging.INFO)
|
logging.basicConfig(filename='bot.log', level=logging.INFO)
|
||||||
|
|
||||||
# Define intents
|
|
||||||
intents = discord.Intents.all()
|
|
||||||
|
|
||||||
# Connect to SQLite database
|
|
||||||
with sqlite3.connect('member_data.db') as conn:
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
# Create table with fields if it doesn't exist already
|
|
||||||
c.execute('''CREATE TABLE IF NOT EXISTS members (
|
|
||||||
user_id INTEGER PRIMARY KEY,
|
|
||||||
username TEXT, nickname TEXT,
|
|
||||||
firstname TEXT, lastname TEXT,
|
|
||||||
join_datetime TEXT,
|
|
||||||
onboarding_status INTEGER,
|
|
||||||
last_change_datetime TEXT
|
|
||||||
)''')
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
|
## Function and Class Definitions ##
|
||||||
|
|
||||||
class PersistentViewBot(commands.Bot):
|
class PersistentViewBot(commands.Bot):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
intents = discord.Intents().all()
|
# Define intents
|
||||||
|
intents = discord.Intents.none()
|
||||||
|
# intents.auto_moderation = True
|
||||||
|
# intents.auto_moderation_configuration = True
|
||||||
|
# intents.auto_moderation_execution = True
|
||||||
|
# intents.bans = True
|
||||||
|
# intents.dm_messages = True
|
||||||
|
# intents.dm_reactions = True
|
||||||
|
# intents.dm_typing = True
|
||||||
|
# intents.emojis = True
|
||||||
|
# intents.emojis_and_stickers = True
|
||||||
|
# intents.guild_messages = True
|
||||||
|
# intents.guild_reactions = True
|
||||||
|
# intents.guild_scheduled_events = True
|
||||||
|
# intents.guild_typing = True
|
||||||
|
intents.guilds = True
|
||||||
|
# intents.integrations = True
|
||||||
|
# intents.invites = True
|
||||||
|
# intents.members = True
|
||||||
|
intents.message_content = True
|
||||||
|
intents.messages = True
|
||||||
|
# intents.moderation = True
|
||||||
|
# intents.presences = True
|
||||||
|
# intents.reactions = True
|
||||||
|
# intents.typing = True
|
||||||
|
# intents.value = True
|
||||||
|
# intents.voice_states = True
|
||||||
|
# intents.webhooks = True
|
||||||
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.
|
||||||
|
|
||||||
client = PersistentViewBot()
|
|
||||||
|
|
||||||
class OnboardModal(discord.ui.Modal, title="Onboarding: "):
|
## Instantiate bot ##
|
||||||
first_name = discord.ui.TextInput(
|
bot = PersistentViewBot()
|
||||||
style=discord.TextStyle.short,
|
|
||||||
label="First name",
|
|
||||||
required=True,
|
|
||||||
placeholder="John "
|
|
||||||
)
|
|
||||||
last_name = discord.ui.TextInput(
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
label="Last Name",
|
|
||||||
required=True,
|
|
||||||
placeholder="Doe"
|
|
||||||
)
|
|
||||||
async def on_submit(self, interaction: discord.InteractionResponse):
|
|
||||||
await interaction.response.defer()
|
|
||||||
await update_nickname(member=self.user, firstname=self.first_name.value, lastname=self.last_name.value)
|
|
||||||
await update_onboard(member=self.user)
|
|
||||||
role_to_add = "Maker"
|
|
||||||
await add_member_to_role(member=self.user, role_name=role_to_add)
|
|
||||||
# print(f'First name: {self.first_name.value}')
|
|
||||||
# print(f'Last Name: {self.last_name.value}')
|
|
||||||
# print(f'User: {self.user.id}')
|
|
||||||
#channel = interaction.guild.get_channel(WELCOME_CHANNEL_ID)
|
|
||||||
#embed = discord.Embed(title="New Onboarding data", description=self.message.value)
|
|
||||||
#embed.set_author(name=self.user.nick)
|
|
||||||
#await channel.send(embed=embed)
|
|
||||||
await interaction.send_message("Thanks for completing onboarding!", ephemeral=True)
|
|
||||||
async def on_error(self, interaction: discord.Interaction, error):
|
|
||||||
...
|
|
||||||
|
|
||||||
class OnboardButtons(discord.ui.View):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__(timeout=None)
|
|
||||||
@discord.ui.button(label="Complete Onboarding", style=discord.ButtonStyle.green, custom_id="1")
|
|
||||||
async def onboard(self, interaction: discord.InteractionResponse, button: discord.ui.Button):
|
|
||||||
onboard_modal = OnboardModal()
|
|
||||||
onboard_modal.user = interaction.user
|
|
||||||
await interaction.response.send_modal(onboard_modal)
|
|
||||||
|
|
||||||
@client.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
print(f'Logged in as {client.user}')
|
print(f'Logged in as {bot.user}')
|
||||||
await welcome_message()
|
# await welcome_message()
|
||||||
try: #sync slash commands
|
|
||||||
synced = await client.tree.sync()
|
|
||||||
print(f'Slash Commands Synced. {str(len(synced))} Total Commands {synced}')
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
print("Members in the DB:")
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
|
||||||
with sqlite3.connect('member_data.db') as conn:
|
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
print("Users in the DB:")
|
||||||
c.execute("SELECT user_id, username, nickname FROM members")
|
c.execute("SELECT id, username FROM users")
|
||||||
for row in c.fetchall():
|
for row in c.fetchall():
|
||||||
print(f' ID: {row[0]} User: {row[1]} Nick: {row[2]}')
|
print(f' ID: {row[0]} User: {row[1]}')
|
||||||
|
print("Servers in the DB:")
|
||||||
|
c.execute("SELECT id, join_url FROM mc_servers")
|
||||||
|
for row in c.fetchall():
|
||||||
|
print(f' ID: {row[0]} URL: {row[1]}')
|
||||||
|
print("Permissions in the DB:")
|
||||||
|
c.execute("SELECT user_id, mc_server_id, permission_level FROM mc_server_users")
|
||||||
|
for row in c.fetchall():
|
||||||
|
print(f' U: {row[0]} S: {row[1]} Perm: {row[2]}')
|
||||||
|
|
||||||
print("Ready.")
|
print("Ready.")
|
||||||
|
|
||||||
@client.command(name='reinit')
|
@bot.tree.command(name='addserver', description="Add a Minecraft server to the bot")
|
||||||
async def cmd_reinit(ctx):
|
@app_commands.describe(
|
||||||
"""Re-initialize a user in the database (i.e. if the bot wasn't listening when they joined)"""
|
status_url="The Minecraft Minder root URL to query/change server status from, like `http://example.com/minecraft.php?password=1234`",
|
||||||
await on_member_join(ctx.author)
|
join_url="The Minecraft server hostname and port for people to join, like `minecraft.example.com:25565`"
|
||||||
await ctx.send("Reinitialized!")
|
)
|
||||||
|
async def addserver(interaction: discord.Interaction, status_url: str, join_url: str):
|
||||||
|
logging.info(f'Addserver: {interaction.user.name} {interaction.user.id} added {status_url} {join_url}')
|
||||||
|
|
||||||
@client.command(name='nick')
|
# Connect to the database using a context manager
|
||||||
async def cmd_nick(ctx):
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
"""View current nickname"""
|
c = conn.cursor()
|
||||||
await ctx.send(f'You are {ctx.author.nick}')
|
|
||||||
|
|
||||||
@client.command(name='setnick')
|
c.execute("INSERT OR REPLACE INTO users (id, username) VALUES (?,?)", (interaction.user.id,interaction.user.name))
|
||||||
async def cmd_setnick(ctx, arg1, arg2):
|
c.execute("INSERT INTO mc_servers (status_url, join_url) VALUES (?,?)", (status_url,join_url))
|
||||||
"""Change nickname (use two words separated by a space)"""
|
server_id = c.lastrowid
|
||||||
await update_nickname(ctx.author, arg1, arg2)
|
c.execute("INSERT OR REPLACE INTO mc_server_users (user_id, mc_server_id, permission_level) VALUES (?,?,?)",
|
||||||
await ctx.send(f'You are now {ctx.author.nick}')
|
(interaction.user.id, server_id, 100))
|
||||||
|
su_id = c.lastrowid
|
||||||
|
|
||||||
@client.command(name='99')
|
conn.commit()
|
||||||
|
logging.warning(f'Addserver: st: {status_url} jo: {join_url} u: {interaction.user.id} s: {server_id} su: {su_id}')
|
||||||
|
await interaction.response.send_message(content="Added!", ephemeral=True)
|
||||||
|
|
||||||
|
@bot.tree.command(name='adduser', description="Give a user privileges to control your Minecraft server")
|
||||||
|
@app_commands.describe(member="The member you want to add", server_id="The internal server ID to add them to")
|
||||||
|
async def adduser(interaction: discord.Interaction, member: discord.Member, server_id: int):
|
||||||
|
logging.info(f'Adduser: {member.name} {member.id} {server_id}')
|
||||||
|
|
||||||
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
c.execute("SELECT s.id, su.permission_level FROM mc_servers s JOIN mc_server_users su ON su.user_id = ? AND su.mc_server_id = ? AND su.mc_server_id = s.id", (interaction.user.id,server_id))
|
||||||
|
row = c.fetchone()
|
||||||
|
if row:
|
||||||
|
if row[1] >= 100:
|
||||||
|
c.execute("INSERT OR REPLACE INTO users (id, username) VALUES (?,?)", (member.id,member.name))
|
||||||
|
|
||||||
|
c.execute("SELECT user_id, mc_server_id FROM mc_server_users WHERE user_id = ? AND mc_server_id = ?", (member.id, server_id))
|
||||||
|
if c.fetchone():
|
||||||
|
logging.warning(f'Adduser: u: {interaction.user.id} m: {member.name} s: {row[0]} has perm')
|
||||||
|
await interaction.response.send_message(content="{} is already added to the server!".format(member.mention), ephemeral=True)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
c.execute("INSERT OR REPLACE INTO mc_server_users (user_id, mc_server_id, permission_level) VALUES (?,?,?)",
|
||||||
|
(member.id, row[0], 1))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
logging.warning(f'Adduser: u: {interaction.user.id} m: {member.name} s: {row[0]}')
|
||||||
|
await interaction.response.send_message(content="Added {} to the server!".format(member.mention))
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(f'Adduser: u: {interaction.user.id} m: {member.name} s: {server_id} privfail')
|
||||||
|
await interaction.response.send_message(content="You don't have enough privileges to add users to server #{}! ({}<100)".format(server_id, row[1]), ephemeral=True)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(f'Adduser: u: {interaction.user.id} m: {member.name} s: {server_id} permfail')
|
||||||
|
await interaction.response.send_message(content="You don't have permission to access server #{}!".format(server_id), ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
@bot.tree.command(name='removeuser', description="Remove a user from the ability to control your Minecraft server")
|
||||||
|
@app_commands.describe(member="The member you want to remove", server_id="The internal server ID to remove them from")
|
||||||
|
async def removeuser(interaction: discord.Interaction, member: discord.Member, server_id: int):
|
||||||
|
logging.info(f'Removeuser: {member.name} {member.id} {server_id}')
|
||||||
|
|
||||||
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
c.execute("SELECT s.id, su.permission_level FROM mc_servers s JOIN mc_server_users su ON su.user_id = ? AND su.mc_server_id = ? AND su.mc_server_id = s.id", (interaction.user.id,server_id))
|
||||||
|
row = c.fetchone()
|
||||||
|
if row:
|
||||||
|
if row[1] >= 100:
|
||||||
|
c.execute("SELECT user_id, mc_server_id FROM mc_server_users WHERE user_id = ? AND mc_server_id = ?", (member.id, server_id))
|
||||||
|
if c.fetchone() == None:
|
||||||
|
logging.warning(f'Removeuser: u: {interaction.user.id} m: {member.name} s: {row[0]} doesn\'t have perm')
|
||||||
|
await interaction.response.send_message(content="{} is already removed from the server!".format(member.mention), ephemeral=True)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
c.execute("DELETE FROM mc_server_users WHERE user_id=? AND mc_server_id=?", (member.id, row[0]))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
logging.warning(f'Removeuser: u: {interaction.user.id} m: {member.name} s: {row[0]}')
|
||||||
|
await interaction.response.send_message(content="Removed {} from the server!".format(member.mention), ephemeral=True)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(f'Removeuser: u: {interaction.user.id} m: {member.name} s: {server_id} privfail')
|
||||||
|
await interaction.response.send_message(content="You don't have enough privileges to remove users from server #{}! ({}<100)".format(server_id, row[1]), ephemeral=True)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(f'Removeuser: u: {interaction.user.id} m: {member.name} s: {server_id} permfail')
|
||||||
|
await interaction.response.send_message(content="You don't have permission to access server #{}!".format(server_id), ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
@bot.tree.command(name='listservers', description="Show the IDs of the MC servers you have access to")
|
||||||
|
async def listservers(interaction: discord.Interaction):
|
||||||
|
logging.info(f'Listservers: {interaction.user.name}')
|
||||||
|
|
||||||
|
# Connect to the database using a context manager
|
||||||
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
c.execute("SELECT id, status_url, join_url FROM mc_servers s JOIN mc_server_users su ON su.user_id = ?", (interaction.user.id,))
|
||||||
|
|
||||||
|
o = ""
|
||||||
|
for row in c.fetchall():
|
||||||
|
o += '- **ID**: {}\n - **Status URL**: {}\n - **Join URL**: {}\n'.format(row[0], row[1], row[2])
|
||||||
|
if o == "":
|
||||||
|
o = "No servers."
|
||||||
|
|
||||||
|
await interaction.response.send_message(content=o, ephemeral=True)
|
||||||
|
|
||||||
|
@bot.tree.command(name='status', description="Minecraft Status")
|
||||||
|
async def cmd_status(interaction: discord.Interaction):
|
||||||
|
logging.warning(f'Member {interaction.user} queried Minecraft status.')
|
||||||
|
|
||||||
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Todo: select "this guild's/channel's" server not just the first match
|
||||||
|
c.execute("SELECT s.id, su.permission_level, s.status_url, s.join_url FROM mc_servers s JOIN mc_server_users su ON su.user_id = ? AND su.mc_server_id = s.id", (interaction.user.id,))
|
||||||
|
row = c.fetchone()
|
||||||
|
if row:
|
||||||
|
if row[1] >= 1:
|
||||||
|
logging.warning(f'Member {interaction.user} started Minecraft.')
|
||||||
|
msg = await interaction.response.defer(thinking=True)
|
||||||
|
res = requests.post(row[2], data={"action": "status"})
|
||||||
|
await interaction.followup.send(content=f'{res.text.capitalize()}\nJoin at `{row[3]}`')
|
||||||
|
|
||||||
|
@bot.tree.command(name='start', description="Start Minecraft")
|
||||||
|
async def cmd_start(interaction: discord.Interaction):
|
||||||
|
logging.info(f'Start: {interaction.user.name} {interaction.user.id}')
|
||||||
|
|
||||||
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Todo: select "this guild's/channel's" server not just the first match
|
||||||
|
c.execute("SELECT s.id, su.permission_level, s.status_url, s.join_url FROM mc_servers s JOIN mc_server_users su ON su.user_id = ? AND su.mc_server_id = s.id", (interaction.user.id,))
|
||||||
|
row = c.fetchone()
|
||||||
|
if row:
|
||||||
|
if row[1] >= 1:
|
||||||
|
logging.warning(f'Member {interaction.user} started Minecraft.')
|
||||||
|
msg = await interaction.response.defer(thinking=True)
|
||||||
|
res = requests.post(row[2], data={"action": "on"})
|
||||||
|
cont=True
|
||||||
|
count=0
|
||||||
|
while cont:
|
||||||
|
count += 1
|
||||||
|
time.sleep(5)
|
||||||
|
res = requests.post(row[2], data={"action": "status"})
|
||||||
|
if "running" in res.text:
|
||||||
|
await interaction.followup.send(content=f'Started: {res.text.capitalize()}\nJoin at `{row[3]}`')
|
||||||
|
cont=False
|
||||||
|
elif count > 10:
|
||||||
|
await interaction.followup.send(content=f'Starting timed out: {res.text.capitalize()}')
|
||||||
|
cont=False
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(f'Start: u: {interaction.user.id} m: {interaction.user.name} s: {row[0]} permfail')
|
||||||
|
await interaction.response.send_message(content="You don't have permission to access server #{}!".format(row[0]), ephemeral=True)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(f'Start: u: {interaction.user.id} m: {interaction.user.name} permfail')
|
||||||
|
await interaction.response.send_message(content="You don't have permission to access any servers!", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
@bot.command(name='99')
|
||||||
async def cmd_nine_nine(ctx):
|
async def cmd_nine_nine(ctx):
|
||||||
brooklyn_99_quotes = [
|
brooklyn_99_quotes = [
|
||||||
'I\'m the human form of the 💯 emoji.',
|
'I\'m the human form of the 💯 emoji.',
|
||||||
|
@ -213,73 +266,51 @@ async def cmd_nine_nine(ctx):
|
||||||
response = random.choice(brooklyn_99_quotes)
|
response = random.choice(brooklyn_99_quotes)
|
||||||
await ctx.send(response)
|
await ctx.send(response)
|
||||||
|
|
||||||
@client.command(name='shutdown')
|
@bot.command(name='shutdown')
|
||||||
async def cmd_shutdown(ctx):
|
async def cmd_shutdown(ctx):
|
||||||
"""Shutdown the bot"""
|
"""Shutdown the bot"""
|
||||||
await ctx.send("Shutting down!")
|
await ctx.send("Shutting down!")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# @client.event
|
@bot.command(name='sync')
|
||||||
# async def on_message(message):
|
async def cmd_sync(ctx):
|
||||||
# if message.author == client.user:
|
synced = await bot.tree.sync()
|
||||||
# return
|
o = f'{len(synced)}/{len(bot.tree.get_commands())} Commands Synced: ({", ".join([str(o.name) for o in synced])})'
|
||||||
|
await ctx.send(o, ephemeral=True)
|
||||||
|
logging.warning(o)
|
||||||
|
|
||||||
# brooklyn_99_quotes = [
|
@bot.event
|
||||||
# '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
|
|
||||||
async def on_member_join(member):
|
|
||||||
await welcome_message()
|
|
||||||
|
|
||||||
with sqlite3.connect('member_data.db') as conn:
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
# 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
|
|
||||||
# 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")
|
|
||||||
@app_commands.describe(member="The member you want to remove")
|
|
||||||
async def remove(interaction: discord.Integration, member: discord.Member):
|
|
||||||
await remove_user(member)
|
|
||||||
await interaction.response.send_message(f"User {member.display_name} Removed", ephemeral=True)
|
|
||||||
|
|
||||||
@client.event
|
|
||||||
async def on_member_remove(member):
|
async def on_member_remove(member):
|
||||||
# Log member leave
|
# Log member leave
|
||||||
logging.warning(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
|
## Runtime ##
|
||||||
TOKEN = os.getenv('BOT_TOKEN')
|
|
||||||
WELCOME_CHANNEL_ID = os.getenv('WELCOME_CHANNEL_ID')
|
# Connect to SQLite database
|
||||||
GUILD_ID = str(os.getenv('GUILD_ID'))
|
with sqlite3.connect('bot_data.db') as conn:
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Create table with fields if it doesn't exist already
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
username TEXT
|
||||||
|
)''')
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS mc_servers (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
status_url TEXT,
|
||||||
|
join_url TEXT
|
||||||
|
)''')
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS mc_server_users (
|
||||||
|
user_id TEXT,
|
||||||
|
mc_server_id TEXT,
|
||||||
|
permission_level INTEGER,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id),
|
||||||
|
FOREIGN KEY (mc_server_id) REFERENCES mc_servers (id),
|
||||||
|
PRIMARY KEY (user_id, mc_server_id)
|
||||||
|
)''')
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
# Start bot
|
# Start bot
|
||||||
client.run(TOKEN)
|
bot.run(TOKEN)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user