DiscordApplicationBot/bot.py

226 lines
9.8 KiB
Python

# db - msg_id, user_id, guild_id
import asyncio
import discord
import os
import json
from dotenv import load_dotenv
from discord.ui import Modal, InputText
from discord.utils import get
from discord.ext import commands
from dbutil import MessageDB
from dbutil import GuildAppDB
load_dotenv()
TOKEN = os.getenv("TOKEN")
SERVER_NAME = os.getenv("SERVER_NAME")
CHANNEL_ID = os.getenv("CHANNEL_ID")
bot = discord.Bot(intents=discord.Intents.all())
channel_id = int(CHANNEL_ID)
questions = [
"What is your Minecraft username?",
"How did you learn about CraftTopia? (If it was from a friend or a website we would like to know either who or where just to know where credit is due)",
"Have you been a part of a minecraft community before, if so, let us know what your experience was with that community.",
"How old are you?",
"Do you have a good microphone for proximity chat?",
"Do you plan on spending at least 2-3 hours a week on the server (our current definition of active)",
"What will you be able to do to help us grow and build our community?",
"Any other questions or concerns?"
]
max_questions = len(questions)
@bot.event
async def on_ready():
bot.add_view(ApplicationButtonsView())
bot.add_view(ApplicationStartButtonView())
activity = discord.Activity(name=f"{len(bot.guilds)} guilds", type=discord.ActivityType.listening)
await bot.change_presence(activity=activity, status = discord.Status.online)
print(f"Logged in as {bot.user}")
for i in bot.guilds:
if str(i.id) not in GuildAppDB.get_all_guilds():
GuildAppDB.create_guild(str(i.id), i.name)
print(f"entry for {i.id} created")
@bot.event
async def on_guild_join(guild):
activity = discord.Activity(name=f"{len(bot.guilds)} guilds", type=discord.ActivityType.listening)
await bot.change_presence(activity=activity, status = discord.Status.online)
GuildAppDB.create_guild(str(guild.id), guild.name)
print(f"Joined guild {guild.name}: {guild.id}")
@bot.event
async def on_guild_remove(guild):
activity = discord.Activity(name=f"{len(bot.guilds)} guilds", type=discord.ActivityType.listening)
await bot.change_presence(activity=activity, status = discord.Status.online)
print(f"Removed from guild {guild.name}: {guild.id}")
@commands.has_permissions(administrator=True)
@bot.slash_command(description = "Command used to set up the application prompt")
async def start_button(ctx):
embed = discord.Embed(title="**Start your application!**")
embed.add_field(name="Click the button below to start your application", value="", inline=False)
embed.set_footer(text="Made by @anorak01", icon_url="https://cdn.discordapp.com/avatars/269164865480949760/a1af9962da20d5ddaa136043cf45d015?size=1024")
appStartView = ApplicationStartButtonView()
await ctx.response.send_message("Message set up", ephemeral=True)
await ctx.channel.send(embeds=[embed], view=appStartView)
@start_button.error
async def on_application_command_error(ctx, error):
if isinstance(error, commands.MissingPermissions):
await ctx.respond("You need Administrator permissions to use this command", ephemeral=True)
else:
raise error
# View with button that starts the application process
class ApplicationStartButtonView(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
@discord.ui.button(
label="Start application!",
style=discord.ButtonStyle.green,
custom_id=f"persistent:start_application",
)
async def start_app(self, button: discord.ui.Button, interaction: discord.Interaction):
user = await interaction.user.create_dm()
embedd = discord.Embed(title=f'CreaTopia Application', description="Hey! Your application has started. You have 300 seconds to complete it.")
embedd.add_field(value=f'You can cancel the application by answering "cancel" to any of the questions', name="", inline=False)
embedd.set_footer(text="Made by @anorak01", icon_url="https://cdn.discordapp.com/avatars/269164865480949760/a1af9962da20d5ddaa136043cf45d015?size=1024")
try:
await user.send(embed=embedd)
except discord.Forbidden:
await interaction.response.send_message(content="Can't start application. Please allow direct messages from server members in your privacy settings.", ephemeral=True)
return
await interaction.response.send_message(content="Application started", ephemeral=True)
application = {'userId': interaction.user.id}
for i in range(0, max_questions):
try:
embed = discord.Embed(title=f'Question [{i+1}/{max_questions}]', description=questions[i])
await user.send(embed=embed)
response = await bot.wait_for('message', check=lambda m: m.author == interaction.user and m.channel == user, timeout=300)
if response.content.startswith("cancel"):
await user.send("Your application has been cancelled")
return
else:
application[f'question{i}'] = response.content
except asyncio.TimeoutError:
await user.send(content="As you haven't replied in 300 seconds, your application has been cancelled")
return
try:
with open('applications.json', 'r') as f:
data = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
data = []
data.append(application)
with open('applications.json', 'w') as f:
json.dump(data, f)
channel = bot.get_channel(channel_id)
embed = discord.Embed(title='Application: ' + interaction.user.display_name)
for i in range(0, max_questions):
embed.add_field(name=f'{questions[i]}', value=application[f'question{i}'], inline=False)
embed.set_footer(text=f"Applicant ID: {interaction.user.id}")
appView = ApplicationButtonsView()
msg = await channel.send(embed=embed, view=appView)
print(msg.id)
MessageDB.add_application_msg(msg.id, interaction.user.id, interaction.guild.id)
await user.send('Thank you for applying!')
# View containing accept and decline buttons for each application
class ApplicationButtonsView(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
@discord.ui.button(
label="Accept",
style=discord.ButtonStyle.green,
custom_id=f"persistent:accept",
)
async def accept(self, button: discord.ui.Button, interaction: discord.Interaction):
msg_id = str(interaction.message.id)
user_id, guild_id = MessageDB.get_application_msg(msg_id)
modal = ApplicationModal(title=f"Accepting: {bot.get_user(user_id).display_name}")
modal.set_action("acc")
modal.add_item(discord.ui.InputText(label=f"Reason: "))
await interaction.response.send_modal(modal)
@discord.ui.button(
label="Decline",
style=discord.ButtonStyle.red,
custom_id=f"persistent:decline",
)
async def decline(self, button: discord.ui.Button, interaction: discord.Interaction):
msg_id = str(interaction.message.id)
user_id, guild_id = MessageDB.get_application_msg(msg_id)
modal = ApplicationModal(title=f"Declining: {bot.get_user(user_id).display_name}")
modal.set_action("dec")
modal.add_item(discord.ui.InputText(label=f"Reason: "))
await interaction.response.send_modal(modal)
# Modal functioning as a callback for Accepting/Declining application
class ApplicationModal(discord.ui.Modal):
def set_action(self, action):
self.action = action
async def callback(self, interaction: discord.Interaction):
reason = self.children[0].value
msg_id = str(interaction.message.id)
user_id, guild_id = MessageDB.get_application_msg(msg_id)
if self.action == "acc":
user = await bot.get_user(user_id).create_dm()
await user.send(f"You have been accepted to the CreatTopia Minecraft server!")
await user.send(f"Reason: {reason}")
await interaction.response.send_message(content="Application accepted", ephemeral=True)
role = get(interaction.message.guild.roles, name="CreatTopian")
await discord.utils.get(interaction.message.guild.members, id=int(user_id)).add_roles(role)
emb = interaction.message.embeds[0]
emb.colour = discord.Colour.green()
embed = discord.Embed(title='Accepted')
embed.add_field(name=f'Reason:', value=reason, inline=False)
embed.colour = discord.Colour.green()
await interaction.followup.edit_message(message_id = interaction.message.id, embeds=[emb, embed])
view = discord.ui.View.from_message(interaction.message)
view.disable_all_items()
await interaction.followup.edit_message(message_id = interaction.message.id, view = view)
if self.action == "dec":
user = await bot.get_user(user_id).create_dm()
await user.send(f"You have been declined access to the CreatTopia Minecraft server.")
await user.send(f"Reason: {reason}")
await interaction.response.send_message(content="Application declined", ephemeral=True)
emb = interaction.message.embeds[0]
emb.colour = discord.Colour.red()
embed = discord.Embed(title='Declined')
embed.add_field(name=f'Reason:', value=reason, inline=False)
embed.colour = discord.Colour.red()
await interaction.followup.edit_message(message_id = interaction.message.id, embeds=[emb, embed])
view = discord.ui.View.from_message(interaction.message)
view.disable_all_items()
await interaction.followup.edit_message(message_id = interaction.message.id, view = view)
# end
bot.run(TOKEN)