15 July Build
Implemented YAML Implemented basic client introspection for guild metadata Added todo tracker
This commit is contained in:
parent
c123186984
commit
ef6c49b5f8
8
.gitignore
vendored
8
.gitignore
vendored
@ -88,14 +88,14 @@ ipython_config.py
|
|||||||
# pyenv
|
# pyenv
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
# .python-version
|
.python-version
|
||||||
|
|
||||||
# pipenv
|
# pipenv
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
# install all needed dependencies.
|
# install all needed dependencies.
|
||||||
#Pipfile.lock
|
Pipfile.lock
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
@ -140,6 +140,10 @@ dmypy.json
|
|||||||
# Cython debug symbols
|
# Cython debug symbols
|
||||||
cython_debug/
|
cython_debug/
|
||||||
|
|
||||||
|
# Local Dev Env Configs
|
||||||
|
Scripts/
|
||||||
|
pyvenv.cfg
|
||||||
|
|
||||||
# ---> VisualStudioCode
|
# ---> VisualStudioCode
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"editor.insertSpaces": false,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"python.pythonPath": "./app/Scripts/python.exe",
|
||||||
|
}
|
24
TODO.md
Normal file
24
TODO.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# To Do
|
||||||
|
|
||||||
|
## Bot Architecture
|
||||||
|
[] Simplify directory tree
|
||||||
|
|
||||||
|
## Bot Functionality
|
||||||
|
[] Delete Commands Function
|
||||||
|
[] Register Commands Function
|
||||||
|
[] Infer Permissions from Config
|
||||||
|
[] Dynamic Command Prefixes
|
||||||
|
[] Infer Games from Server Structure
|
||||||
|
|
||||||
|
## Event Listeners
|
||||||
|
|
||||||
|
### Review Configs When
|
||||||
|
[] Guild Changing Ownership
|
||||||
|
[] Roles Modified
|
||||||
|
[] Mod Channel Deleted
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
[] Migrate existing bot commands
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
[] Review documentation
|
10
app/bot.py
10
app/bot.py
@ -1,9 +1,12 @@
|
|||||||
# Import Dependencies
|
# Import Dependencies
|
||||||
import os
|
import os
|
||||||
import pymongo
|
import configparser
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands, tasks
|
from discord.ext import commands, tasks
|
||||||
|
|
||||||
|
configFile = './config.ini'
|
||||||
|
dataDir = './data'
|
||||||
|
|
||||||
# Set Intents
|
# Set Intents
|
||||||
intents = discord.Intents.all()
|
intents = discord.Intents.all()
|
||||||
intents.typing = True
|
intents.typing = True
|
||||||
@ -17,8 +20,7 @@ p = '¬'
|
|||||||
# Define Global State Dictionary
|
# Define Global State Dictionary
|
||||||
state = {}
|
state = {}
|
||||||
|
|
||||||
# Create Clients
|
# Clients
|
||||||
dbClient = pymongo.MongoClient(host='geasbot-db', username=os.environ['MONGO_INITDB_ROOT_USERNAME'], password=os.environ['MONGO_INITDB_ROOT_PASSWORD'], authsource='admin', serverSelectionTimeoutMS=1000)
|
|
||||||
client = commands.Bot(command_prefix=p, description=f'Geas Server Bot v {os.getenv("BOT_VERSION")}. This is a bot to facilitate setting up game channels on the Geas server. The prefix for the bot is {p}. You can interact with and manipulate game channels that have been created with this bot by @-mentioning the relevant role associated with the game.', intents=intents)
|
client = commands.Bot(command_prefix=p, description=f'Geas Server Bot v {os.getenv("BOT_VERSION")}. This is a bot to facilitate setting up game channels on the Geas server. The prefix for the bot is {p}. You can interact with and manipulate game channels that have been created with this bot by @-mentioning the relevant role associated with the game.', intents=intents)
|
||||||
|
|
||||||
# Define Game Times Dictionary
|
# Define Game Times Dictionary
|
||||||
@ -203,6 +205,7 @@ async def on_command_error(ctx,error):
|
|||||||
# On Ready
|
# On Ready
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
|
|
||||||
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f'{p} commands'))
|
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f'{p} commands'))
|
||||||
print(f'Bot has logged in as {client.user.name} responding to prefix {p}')
|
print(f'Bot has logged in as {client.user.name} responding to prefix {p}')
|
||||||
print(f'Geas Server Bot version {os.getenv("BOT_VERSION")} by Vivek Santayana')
|
print(f'Geas Server Bot version {os.getenv("BOT_VERSION")} by Vivek Santayana')
|
||||||
@ -327,7 +330,6 @@ async def defineBotrole(ctx, arg):
|
|||||||
if not arg.startswith('<@&'):
|
if not arg.startswith('<@&'):
|
||||||
raise commands.CommandError('Invalid argument. The argument must @ a role.')
|
raise commands.CommandError('Invalid argument. The argument must @ a role.')
|
||||||
dbName = str(ctx.guild.id)
|
dbName = str(ctx.guild.id)
|
||||||
db = dbClient[dbName]
|
|
||||||
colName = 'settings'
|
colName = 'settings'
|
||||||
r = ctx.guild.get_role(int(arg[3:-1]))
|
r = ctx.guild.get_role(int(arg[3:-1]))
|
||||||
if dbName not in state:
|
if dbName not in state:
|
||||||
|
0
app/data/.gitkeep
Normal file
0
app/data/.gitkeep
Normal file
4
app/data/config.yml
Normal file
4
app/data/config.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
'864651943820525609':
|
||||||
|
adminroles: []
|
||||||
|
name: Test
|
||||||
|
owner: 493694762210033664
|
117
app/dev.py
Normal file
117
app/dev.py
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import os # OS Locations
|
||||||
|
from dotenv import load_dotenv # Import OS variables from Dotenv file.
|
||||||
|
load_dotenv() # Load Dotenv. Delete this for production
|
||||||
|
import yaml # Parser for yaml files for config settings.
|
||||||
|
import json # Json Library to manage json Data files
|
||||||
|
import discord # Main Lib
|
||||||
|
from discord.ext import commands # Commands module
|
||||||
|
from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library
|
||||||
|
from discord_slash.utils.manage_commands import create_choice, create_option # Slash Command features
|
||||||
|
import logging
|
||||||
|
|
||||||
|
## Define YAML functions
|
||||||
|
|
||||||
|
def yaml_load(filepath):
|
||||||
|
### Loads a YAML file
|
||||||
|
with open(filepath, 'r') as file:
|
||||||
|
data = yaml.load(file)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def yaml_dump(data, filepath):
|
||||||
|
### Dumps a YAML file
|
||||||
|
with open(filepath, 'w') as file:
|
||||||
|
yaml.dump(data, file)
|
||||||
|
|
||||||
|
# Locate or create config File
|
||||||
|
configFile = './data/config.yml'
|
||||||
|
|
||||||
|
if not os.path.exists(configFile):
|
||||||
|
yaml_dump({},configFile)
|
||||||
|
|
||||||
|
# Locate Cogs Directory
|
||||||
|
cogsDir = 'dev_cogs'
|
||||||
|
|
||||||
|
## Logging configuration imported boilerplate from Discord Py Docs
|
||||||
|
logger = logging.getLogger('discord')
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
|
||||||
|
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# Define Clients
|
||||||
|
client = commands.Bot(
|
||||||
|
intents=discord.Intents.all(),
|
||||||
|
command_prefix='¬'
|
||||||
|
)
|
||||||
|
slash = SlashCommand(
|
||||||
|
client,
|
||||||
|
sync_commands = True,
|
||||||
|
sync_on_cog_reload = True
|
||||||
|
)
|
||||||
|
# sync_on_reload is an important parameter that will become relevant when having to reload cogs on changing bot configs.
|
||||||
|
|
||||||
|
# Define Config keys
|
||||||
|
configKeys = ['adminroles', 'botrole', 'modchannel', 'name', 'owner', 'prefix']
|
||||||
|
|
||||||
|
# Create list of guild IDs the bot is currently in
|
||||||
|
# guild_ids = [864651943820525609]
|
||||||
|
guild_ids = []
|
||||||
|
|
||||||
|
# Retrieve IDs from config file
|
||||||
|
conf = yaml_load(configFile)
|
||||||
|
for guild in conf:
|
||||||
|
if int(guild) not in guild_ids:
|
||||||
|
guild_ids.append(int(guild))
|
||||||
|
# Will check on bot ready if any other guilds are missing fron configs.
|
||||||
|
|
||||||
|
@client.command(name='foobartest')
|
||||||
|
async def foobartest(ctx):
|
||||||
|
f = await utils.manage_commands.get_all_commands(client.user.id,os.getenv('TEST_3_TOKEN'),guild_id=ctx.guild.id)
|
||||||
|
print(f)
|
||||||
|
|
||||||
|
def loadCommands():
|
||||||
|
for cogfile in os.listdir(f'./{cogsDir}/commands'):
|
||||||
|
logging.info('Loading commands.')
|
||||||
|
if cogfile.endswith('.py'):
|
||||||
|
c = cogfile[:-3]
|
||||||
|
client.load_extension(f'{cogsDir}.commands.{c}')
|
||||||
|
print(f'Loaded Cog ./{cogsDir}/{c}')
|
||||||
|
logging.info(f'Loaded Cog ./app/{cogsDir}/commands/{c}')
|
||||||
|
|
||||||
|
def unloadCommands():
|
||||||
|
for cogfile in os.listdir(f'./{cogsDir}/commands'):
|
||||||
|
logging.info('Unloading commands.')
|
||||||
|
if cogfile.endswith('.py'):
|
||||||
|
c = cogfile[:-3]
|
||||||
|
client.unload_extension(f'{cogsDir}.commands.{c}')
|
||||||
|
print(f'Unloaded Cog ./{cogsDir}/{c}')
|
||||||
|
logging.info(f'Unloaded Cog ./{cogsDir}/commands/{c}')
|
||||||
|
|
||||||
|
def reloadCommands():
|
||||||
|
unloadCommands()
|
||||||
|
loadCommands()
|
||||||
|
|
||||||
|
def loadAllCogs():
|
||||||
|
for cogfile in os.listdir(f'./{cogsDir}'):
|
||||||
|
logging.info('Loading cogs.')
|
||||||
|
if cogfile.endswith('.py'):
|
||||||
|
c = cogfile[:-3]
|
||||||
|
client.load_extension(f'{cogsDir}.{c}')
|
||||||
|
print(f'Loaded Cog ./{cogsDir}/{c}')
|
||||||
|
logging.info(f'Loaded Cog ./app/{cogsDir}/{c}')
|
||||||
|
|
||||||
|
def unloadAllCogs():
|
||||||
|
for cogfile in os.listdir(f'./{cogsDir}'):
|
||||||
|
logging.info('Unloading cogs.')
|
||||||
|
if cogfile.endswith('.py'):
|
||||||
|
c = cogfile[:-3]
|
||||||
|
client.unload_extension(f'{cogsDir}.{c}')
|
||||||
|
print(f'Unloaded Cog ./{cogsDir}/{c}')
|
||||||
|
logging.info(f'Unloaded Cog ./{cogsDir}/{c}')
|
||||||
|
|
||||||
|
def reloadAllCogs():
|
||||||
|
unloadAllCogs()
|
||||||
|
loadAllCogs()
|
||||||
|
|
||||||
|
loadAllCogs()
|
||||||
|
client.run(os.getenv('TEST_3_TOKEN'))
|
37
app/dev_cogs/commands/config.py
Normal file
37
app/dev_cogs/commands/config.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import os # OS Locations
|
||||||
|
import yaml # YAML parser for Bot config files
|
||||||
|
import json # Json Library to manage json Data files
|
||||||
|
import discord # Main Lib
|
||||||
|
from discord.ext import commands # Commands module
|
||||||
|
from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library
|
||||||
|
from discord_slash.utils.manage_commands import create_choice, create_option # Slash Command features
|
||||||
|
|
||||||
|
from dev import guild_ids
|
||||||
|
|
||||||
|
##### Configuration Cog
|
||||||
|
class Configuration(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
@cog_ext.cog_slash(
|
||||||
|
# base='botrole',
|
||||||
|
# subcommand_group='configure',
|
||||||
|
name='configure',
|
||||||
|
description='Parameter to define the role assigned to the dice bots.',
|
||||||
|
# base_description='Command to configure the various guild parameters.',
|
||||||
|
# subcommand_group_description='These are configuration commands to set up the various guild parameters.',
|
||||||
|
guild_ids=guild_ids
|
||||||
|
# options=[
|
||||||
|
# create_option(
|
||||||
|
# name='botrole',
|
||||||
|
# description='The role that the dice bots are assigned in order to access the text channels.'
|
||||||
|
# type=8,
|
||||||
|
# required=True
|
||||||
|
# )
|
||||||
|
# ]
|
||||||
|
)
|
||||||
|
async def _configure(self, ctx:SlashContext, option):
|
||||||
|
await ctx.send(f'The `botrole` for the guild `{ctx.guild.name}` has been set to `{option}`.')
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Configuration(client))
|
51
app/dev_cogs/commands/debug.py
Normal file
51
app/dev_cogs/commands/debug.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv # Import OS variables from Dotenv file.
|
||||||
|
load_dotenv() # Load Dotenv. Delete this for production
|
||||||
|
import discord # Main Lib
|
||||||
|
from discord.ext import commands # Commands module
|
||||||
|
from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library
|
||||||
|
from discord_slash.utils.manage_commands import create_choice, create_option # Slash Command features
|
||||||
|
|
||||||
|
from dev import guild_ids, unloadAllCogs, loadAllCogs, reloadAllCogs
|
||||||
|
|
||||||
|
##### Debug Cog
|
||||||
|
class Debug(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
@cog_ext.cog_slash(
|
||||||
|
name='reload',
|
||||||
|
description='Reloads all cogs',
|
||||||
|
guild_ids=guild_ids
|
||||||
|
)
|
||||||
|
async def _reload(self, ctx:SlashContext):
|
||||||
|
reloadAllCogs()
|
||||||
|
await ctx.send('Reloading Cogs.')
|
||||||
|
|
||||||
|
@cog_ext.cog_slash(
|
||||||
|
name='deleteAll',
|
||||||
|
description='Deletes all Slash Commands',
|
||||||
|
guild_ids=guild_ids
|
||||||
|
)
|
||||||
|
async def _deleteAll(self, ctx:SlashContext):
|
||||||
|
await utils.manage_commands.remove_all_commands(
|
||||||
|
bot_id=self.client.user.id,
|
||||||
|
bot_token=os.getenv('TEST_3_TOKEN'),
|
||||||
|
guild_ids=None
|
||||||
|
)
|
||||||
|
await utils.manage_commands.remove_all_commands(
|
||||||
|
bot_id=self.client.user.id,
|
||||||
|
bot_token=os.getenv('TEST_3_TOKEN'),
|
||||||
|
guild_ids=guild_ids
|
||||||
|
)
|
||||||
|
await ctx.send('Deleted all commands.')
|
||||||
|
|
||||||
|
@commands.command(
|
||||||
|
name='reloadAll'
|
||||||
|
)
|
||||||
|
async def _reloadAll(self, ctx):
|
||||||
|
await ctx.send('Reloading all cogs.')
|
||||||
|
reloadAllCogs()
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Debug(client))
|
90
app/dev_cogs/events.py
Normal file
90
app/dev_cogs/events.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import os # OS Locations
|
||||||
|
import yaml # YAML parser for Bot config files
|
||||||
|
import json # Json Library to manage json Data files
|
||||||
|
import discord # Main Lib
|
||||||
|
from discord.ext import commands # Commands module
|
||||||
|
from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library
|
||||||
|
from discord_slash.utils.manage_commands import create_choice, create_option # Slash Command features
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dev import configFile, guild_ids, unloadAllCogs, loadAllCogs, reloadAllCogs, loadCommands, unloadCommands, reloadCommands, logger, handler, yaml_load, yaml_dump
|
||||||
|
|
||||||
|
##### Event Listener Cog
|
||||||
|
class Events(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_connect(self): ## Actions for when bot logs in and enters ready state
|
||||||
|
print('Bot has connected.')
|
||||||
|
logging.info('Bot has connected.')
|
||||||
|
|
||||||
|
#### Check if the bot is missing any config entries for the guilds it is in, and if it is then add it in.
|
||||||
|
#### N.B.: The way the commands work, the bot will have to list specific guilds in which it will synchronise the commands when it is defining them. So it needs to give a list of all the guilds it is part of when the bot loads, which it draws from the config files.
|
||||||
|
#### Because the bot connects to Discord after it loads, it will not be able to introspect and see what guilds it is part of before the commands are first loaded, and it will only add new guilds to the config files after it has already connected.
|
||||||
|
#### So the bot will have to wait until it first connects, then check if any guilds are missing, and if there are any missing guilds it will need to add them to the list of guilds it has configured, then re-load all of the commands and re-sync them.
|
||||||
|
|
||||||
|
gFlag = False
|
||||||
|
print('Checking for guilds with missing configs.') #### The bot will try to update its configs for any missing values. It will check the accuracy of these values if any relevant parameters of the guild change later.
|
||||||
|
conf = yaml_load(configFile)
|
||||||
|
for g in self.client.guilds:
|
||||||
|
if g.id not in guild_ids:
|
||||||
|
gFlag = True
|
||||||
|
guild_ids.append(g.id)
|
||||||
|
conf[str(g.id)] = {}
|
||||||
|
if 'name' not in conf[str(g.id)]:
|
||||||
|
conf[str(g.id)]['name'] = g.name
|
||||||
|
if 'owner' not in conf[str(g.id)]:
|
||||||
|
conf[str(g.id)]['owner'] = await self.client.fetch_guild(g.id).owner.id
|
||||||
|
if 'adminroles' not in conf[str(g.id)]:
|
||||||
|
conf[str(g.id)]['adminroles'] = []
|
||||||
|
for role in g.roles:
|
||||||
|
if not (role.is_bot_managed() or role.is_integration()) and role.permissions.administrator:
|
||||||
|
conf[str(g.id)]['adminroles'].append(role.id)
|
||||||
|
yaml_dump(conf, configFile)
|
||||||
|
if gFlag:
|
||||||
|
reloadAllCogs()
|
||||||
|
## Because the bot will need to re-sync all the commands with an updated list of guilds, it needs to re-load all cogs.
|
||||||
|
## This should hopefully work with the setting declared earlier to sync on cog reload.
|
||||||
|
|
||||||
|
#### Delete Configs for Guilds that the Bot is no longer in
|
||||||
|
conf = yaml_load(configFile)
|
||||||
|
a = []
|
||||||
|
for g in self.client.guilds:
|
||||||
|
a.append(str(g.id))
|
||||||
|
for g in list(conf):
|
||||||
|
if g not in a:
|
||||||
|
del conf[g]
|
||||||
|
yaml_dump(conf, configFile)
|
||||||
|
|
||||||
|
# for g in self.client.guilds:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_guild_join(self, guild): ## Actions for when bot is added to a new guild for the first time.
|
||||||
|
if guild.id not in guild_ids:
|
||||||
|
guild_ids.append(guild.id)
|
||||||
|
o = f'Adding config entry for guild {g.name}.'
|
||||||
|
print(o)
|
||||||
|
logging.info(o)
|
||||||
|
conf = yaml_load(configFile)
|
||||||
|
conf[str(g.id)] = {}
|
||||||
|
yaml_dump(conf, configFile)
|
||||||
|
reloadAllCogs()
|
||||||
|
## Same reason as above, when the bot is added to a new guild, it will need to re-load all cogs and re-sync commands.
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_guild_remove(self, guild): ## Actions for when the bot is removed from a guild.
|
||||||
|
if guild.id in guild_ids:
|
||||||
|
guild_ids.remove(guild.id)
|
||||||
|
o = f'Removing config entry for guild {g.name}.'
|
||||||
|
print(o)
|
||||||
|
logging.info(o)
|
||||||
|
conf = yaml_load(configFile)
|
||||||
|
conf.pop(str(guild.id), None)
|
||||||
|
yaml_dump(conf, configFile)
|
||||||
|
reloadAllCogs()
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Events(client))
|
189
app/dev_old.py
Normal file
189
app/dev_old.py
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import os # OS Locations
|
||||||
|
from dotenv import load_dotenv # Import OS variables from Dotenv file.
|
||||||
|
load_dotenv() # Load Dotenv. Delete this for production
|
||||||
|
import configparser # Config ini parser for Bot config files
|
||||||
|
import json # Json Library to manage json Data files
|
||||||
|
import discord # Main Lib
|
||||||
|
from discord.ext import commands # Commands module
|
||||||
|
from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library
|
||||||
|
from discord_slash.utils.manage_commands import create_choice, create_option # Slash Command features
|
||||||
|
|
||||||
|
# Locate configuration file
|
||||||
|
configFile = './data/config.ini'
|
||||||
|
|
||||||
|
# Create empty list of current guilds, to be populated Bot load
|
||||||
|
guild_ids = []
|
||||||
|
|
||||||
|
# Config keys
|
||||||
|
configKeys = ['botrole', 'committeerole', 'modchannel', 'prefix']
|
||||||
|
|
||||||
|
# Bot Prefix Function for Regular String Prefix (non-Slash commands)
|
||||||
|
def getPrefix(client,message):
|
||||||
|
conf = configparser.ConfigParser()
|
||||||
|
conf.read(configFile)
|
||||||
|
if message.guild.id in conf.sections():
|
||||||
|
if 'prefix' in conf[message.guild.id]:
|
||||||
|
return conf[message.guild.id]['prefix']
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Define bot client and initialise Slash Command client
|
||||||
|
client = commands.Bot(command_prefix= '¬', intents=discord.Intents.all()) # Regular client set up, but I did not know you could pass a function as a prefix!
|
||||||
|
slash = SlashCommand(client, sync_commands=True) # Enable Slash Command Functionality
|
||||||
|
|
||||||
|
# Starting Bot Initialisation
|
||||||
|
@client.event
|
||||||
|
async def on_guild_join(guild):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# @slash.slash(
|
||||||
|
# name='configure',
|
||||||
|
# description='Configuration command to set up the various parameters for the bot on the server.'
|
||||||
|
# guild_ids=guild_ids,
|
||||||
|
# options = [
|
||||||
|
# create_option(
|
||||||
|
# name='parameter1',
|
||||||
|
# description='Please select the first parameter you would like to configure.',
|
||||||
|
# type=3,
|
||||||
|
# required=True
|
||||||
|
# )
|
||||||
|
# ]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# On Ready
|
||||||
|
@client.event
|
||||||
|
async def on_ready():
|
||||||
|
print('Bot Ready')
|
||||||
|
for guild in client.guilds:
|
||||||
|
guild_ids.append(guild.id)
|
||||||
|
channel = discord.utils.get(guild.text_channels,position=1)
|
||||||
|
print(channel)
|
||||||
|
print(guild_ids)
|
||||||
|
conf = configparser.ConfigParser()
|
||||||
|
conf.read(configFile)
|
||||||
|
undef = []
|
||||||
|
if guild.id in conf.sections(): # Check if there are configs for the guild, and check if configs are complete
|
||||||
|
for i in configKeys:
|
||||||
|
if i not in conf[guild.id]:
|
||||||
|
undef.append(i)
|
||||||
|
if len(undef) == 0: # If none of the key values are undefined, ignore it.
|
||||||
|
channel = discord.utils.get(guild.text_channels,id=conf[guild.id]['modchannel'])
|
||||||
|
output = f'`{client.user.display_name}` has already been configured for the guild `{guild.name}`. \n'
|
||||||
|
output = ''.join([output, f'The `botrole` for the guild `{guild.name}` is {discord.utils.get(guild.roles,id=conf[guild.id]["botrole"]).mention}\n'])
|
||||||
|
output = ''.join([output, f'The `committeerole` for the guild `{guild.name}` is {discord.utils.get(guild.roles,id=conf[guild.id]["committeerole"]).mention}\n'])
|
||||||
|
output = ''.join([output, f'The `modchannel` for the guild `{guild.name}` is {channel.mention}\n'])
|
||||||
|
output = ''.join([output, f'The `prefix` for the guild `{guild.name}` is `{conf[guild.id]["prefix"]}`'])
|
||||||
|
await channel.send(output)
|
||||||
|
break
|
||||||
|
if len(undef) == 0:
|
||||||
|
undef = configKeys.copy()
|
||||||
|
output = f'`{client.user.display_name}` has not been configured for the guild `{guild.name}`. Please define:\n'
|
||||||
|
for u in undef:
|
||||||
|
output = ''.join([output, f'`{u}`\n'])
|
||||||
|
output = ''.join([output, f'using the `/configure` command.'])
|
||||||
|
await channel.send(output)
|
||||||
|
|
||||||
|
|
||||||
|
@slash.slash(
|
||||||
|
name='hello',
|
||||||
|
description='Hello World command',
|
||||||
|
guild_ids=guild_ids,
|
||||||
|
options = [
|
||||||
|
create_option(
|
||||||
|
name='option',
|
||||||
|
description='choose your word',
|
||||||
|
required=True,
|
||||||
|
option_type=3
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def _hello(ctx:SlashContext, option:str):
|
||||||
|
await ctx.send(option)
|
||||||
|
|
||||||
|
@slash.slash(
|
||||||
|
name='mypfp',
|
||||||
|
description='Displays profile picture',
|
||||||
|
guild_ids=guild_ids
|
||||||
|
)
|
||||||
|
async def pfp(ctx):
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f'Avatar of {ctx.author.display_name}',
|
||||||
|
color=discord.Color.teal()
|
||||||
|
).set_image(url=ctx.author.avatar_url)
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
class Cogs(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
@commands.command(description='Sends Pong')
|
||||||
|
async def ping(self, ctx):
|
||||||
|
await ctx.send('pong')
|
||||||
|
|
||||||
|
@cog_ext.cog_slash(name='Ping', description='Sends Pong')
|
||||||
|
async def ping(self, ctx):
|
||||||
|
await ctx.send('pong')
|
||||||
|
|
||||||
|
|
||||||
|
@client.command(name='foo')
|
||||||
|
async def foo(ctx):
|
||||||
|
f = await utils.manage_commands.get_all_commands(client.user.id,os.getenv('TEST_3_TOKEN'),guild_id=ctx.guild.id)
|
||||||
|
print(f)
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
client.add_cog(Cogs(client))
|
||||||
|
|
||||||
|
|
||||||
|
###### Configuration Cog
|
||||||
|
# class Configuration(commands.Cog):
|
||||||
|
# def __init__(self, client):
|
||||||
|
# self.client = client
|
||||||
|
|
||||||
|
# @cog_ext.cog_slash(
|
||||||
|
# # base='botrole',
|
||||||
|
# # subcommand_group='configure',
|
||||||
|
# name='configure',
|
||||||
|
# description='Parameter to define the role that is assigned to the dice bots in this guild so they can access in-game text channels.',
|
||||||
|
# # base_description='Command to configure the various guild parameters.',
|
||||||
|
# # subcommand_group_description='These are configuration commands to set up the various guild parameters.',
|
||||||
|
# guild_ids=guild_ids
|
||||||
|
# # options=[
|
||||||
|
# # create_option(
|
||||||
|
# # name='botrole',
|
||||||
|
# # description='The role that the dice bots are assigned in order to access the text channels.'
|
||||||
|
# # type=8,
|
||||||
|
# # required=True
|
||||||
|
# # )
|
||||||
|
# # ]
|
||||||
|
# )
|
||||||
|
# async def _configure(self, ctx:SlashContext, option):
|
||||||
|
# await ctx.send(f'The `botrole` for the guild `{ctx.guild.name}` has been set to `{option.mention}`.')
|
||||||
|
|
||||||
|
# def setup(client):
|
||||||
|
# client.add_cog(Configuration(client))
|
||||||
|
|
||||||
|
client.run(os.getenv('TEST_3_TOKEN'))
|
||||||
|
|
||||||
|
# guilds = [
|
||||||
|
# 'guild1',
|
||||||
|
# 'guild2',
|
||||||
|
# 'guild3'
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# configFile = './config.ini'
|
||||||
|
|
||||||
|
# config = configparser.RawConfigParser()
|
||||||
|
|
||||||
|
# for g in guilds:
|
||||||
|
# config.add_section(g)
|
||||||
|
# config.set(g,'botrole',f'<Bot Role> for {g}')
|
||||||
|
# config.set(g,'committeerole',f'<Committee Role> for {g}')
|
||||||
|
|
||||||
|
# with open(configFile,'w') as c:
|
||||||
|
# config.write(c)
|
||||||
|
|
||||||
|
# parser = configparser.ConfigParser()
|
||||||
|
# parser.read(configFile)
|
||||||
|
# print(parser.sections())
|
||||||
|
# print(parser['guild1']['botrole'])
|
@ -1,4 +1,4 @@
|
|||||||
version: '3.4'
|
version: '3.1'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
geasbot-app:
|
geasbot-app:
|
||||||
@ -6,24 +6,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./app:/usr/src/app
|
- ./app:/usr/src/app
|
||||||
restart: always
|
restart: always
|
||||||
depends_on:
|
|
||||||
- geasbot-db
|
|
||||||
environment:
|
environment:
|
||||||
- BOT_TOKEN=${BOT_TOKEN}
|
- BOT_TOKEN=${BOT_TOKEN}
|
||||||
- TEST_TOKEN=${TEST_TOKEN}
|
- TEST_TOKEN=${TEST_TOKEN}
|
||||||
- MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
|
|
||||||
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
|
|
||||||
- BOT_VERSION=${BOT_VERSION}
|
|
||||||
|
|
||||||
geasbot-db:
|
|
||||||
image: mongo:latest
|
|
||||||
volumes:
|
|
||||||
- ./db:/data/db
|
|
||||||
expose:
|
|
||||||
- "27017"
|
|
||||||
environment:
|
|
||||||
- BOT_TOKEN=${BOT_TOKEN}
|
|
||||||
- TEST_TOKEN=${TEST_TOKEN}
|
|
||||||
- MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
|
|
||||||
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
|
|
||||||
- BOT_VERSION=${BOT_VERSION}
|
- BOT_VERSION=${BOT_VERSION}
|
33
maintenance/resources.md
Normal file
33
maintenance/resources.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Resources for Maintaining the Bot
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
1. [Discord Py Documentation](https://discordpy.readthedocs.io/en/stable/index.html)
|
||||||
|
> 1. [Quickstart Guide](https://discordpy.readthedocs.io/en/stable/quickstart.html)
|
||||||
|
> 2. [Set up of Discord Bot Account](https://discordpy.readthedocs.io/en/stable/discord.html)
|
||||||
|
> 3. [**Important**: Primer to Gateway Intents](https://discordpy.readthedocs.io/en/stable/intents.html)
|
||||||
|
`N.B.: this is an important security feature of Discord that is now mandatory to configure and imposes restructions on some of the Bot's functionality unless appropriately configured. Keep an eye on this.`
|
||||||
|
> 4. [Repository with example code](https://github.com/Rapptz/discord.py/tree/v1.7.3/examples)
|
||||||
|
> 5. [Logging Setup](https://discordpy.readthedocs.io/en/stable/logging.html)
|
||||||
|
2. [Discord Py Slash Command Documentation](https://discord-py-slash-command.readthedocs.io/en/latest/index.html)
|
||||||
|
> 1. [Discord Py Slash Command Authentication](https://discord-py-slash-command.readthedocs.io/en/latest/quickstart.html)
|
||||||
|
`N.B.: this is an important security feature in Discord's API, and commands will not be configured unless the applications.commands scope is configured correctly.`
|
||||||
|
> 2. [How to add Slash Commands, including sub-commands](https://discord-py-slash-command.readthedocs.io/en/latest/faq.html#:~:text=If%20your%20slash%20commands%20don,commands%20scope%20in%20that%20guild.)
|
||||||
|
> 3. [Slash Command Cogs Module](https://discord-py-slash-command.readthedocs.io/en/latest/discord_slash.cog_ext.html?highlight=cog#discord_slash.cog_ext.cog_subcommand)
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
1. [YouTube Tutorial by Lucas, starting from the basics](https://www.youtube.com/watch?v=nW8c7vT6Hl4)
|
||||||
|
2. [YouTube tutorial on introduction to Cogs](https://www.youtube.com/watch?v=vQw8cFfZPx0)
|
||||||
|
3. [YouTube tutorial on dynamic prefixes for different servers](https://www.youtube.com/watch?v=yrHbGhem6I4)
|
||||||
|
4. [YouTube tutorial on using the new Slash Command API](https://www.youtube.com/watch?v=CLQ8gfb2jh4)
|
||||||
|
5.
|
||||||
|
|
||||||
|
## Communities
|
||||||
|
|
||||||
|
### Discord Py
|
||||||
|
1. [Discord Py server](https://discord.gg/r3sSKJJ): Discord server to talk to others in the community
|
||||||
|
2. [Discord Py Github issue tracker](https://github.com/Rapptz/discord.py/issues): place to report bugs and issues with the API
|
||||||
|
3. [Discord Py discussion page](https://github.com/Rapptz/discord.py/discussions): wiki for any other discussions
|
||||||
|
|
||||||
|
### Discord Py Slash Commands
|
||||||
|
1. [Discord Py Slash Commands Discord Server](https://discord.gg/KkgMBVuEkx): Discord server with a forum to ask questions in
|
||||||
|
2. [Discord Py Slash Commands Issue Tracker on GitHub](https://github.com/discord-py-slash-commands/discord-py-interactions/issues)
|
Loading…
Reference in New Issue
Block a user