forked from viveksantayana/geas-bot
Debugged membership sign-ups and pitch menu.
Ready for more rigorous testing.
This commit is contained in:
parent
173aeb2a3c
commit
e30e89e7e3
13
README.md
13
README.md
@ -31,6 +31,7 @@ DATA=(Path to data file. The bot defaults to './data/data.yml' if not provided.)
|
||||
LOOKUP=(Path to the game role lookup file. The bot defaults to './data/lookup.yml' if not provided.)
|
||||
GM=(Path to the GM lookup file. The bot defaults to './data/gm.yml' if not provided.)
|
||||
CATEGORIES=(Path to the channel category lookup file. The bot defaults to './data/categories.yml' if not provided.)
|
||||
PITCHES=(Path to the pitches data file. The bot defaults to './data/pitches.yml' if not provided.)
|
||||
BOT_VERSION=(verson string)
|
||||
BOT_MAINTAINER_ID=(Discord user ID of the person maintaining the bot to enable debug features.)
|
||||
```
|
||||
@ -74,7 +75,9 @@ in order for to authenticate as the correct bot.
|
||||
| | | |-- on_guild_role_update.py
|
||||
| | | |-- on_guild_update.py
|
||||
| | | |-- on_message.py
|
||||
| | | `-- on_ready.py
|
||||
| | | |-- on_ready.py
|
||||
| | | `-- secondary
|
||||
| | | `-- pitch_listener.py
|
||||
| | |-- membership
|
||||
| | | |-- membership_verification.py
|
||||
| | | `-- restriction_listener.py
|
||||
@ -194,8 +197,10 @@ There is currently no way of having an exception for the Bot's edits.
|
||||
To reconcile this, the bot would need to work such that the command process that modified games only acted upon the roles, which would then trigger the event listeners to synchronise these changes with the categories, and subsequently the data.
|
||||
Having the bot edit the data in the main command process would mean that there would be conflicts with the simuntaneous execution of parallel threads.
|
||||
|
||||
This works for individual commands, but it breaks down when trying to use the `purge` command because of conflicts causedb by simultaneous changes to the data files.
|
||||
Programming around this will need a further layer of complexity, involving flags checking for R/W operations and a time-out.
|
||||
|
||||
### Membership sign up performance issues
|
||||
|
||||
The way the membership signup prompt works is that it creates a new instance of the process executing for each member who submits a verification request, and the command runs until the verification is complete (either by verifying it or rejecting it).
|
||||
This means that there is a risk that several active instances of the command will run simultaneously if a lot of members submit membership confirmation at once.
|
||||
This should probably also be changed to being a global event listener, with the requisite inforation being passed to the function in the event listener via the custom values of the buttons and drop-down menu options.
|
||||
I have set the member verification prompt to use a global listener to avoid a situation where it creates several backlogged processes when multiple people post sign-ups at the same time.
|
||||
This should also mean that the sign-up prompts should persist over reboots.
|
||||
|
25
app/bot.py
25
app/bot.py
@ -27,34 +27,34 @@ def yaml_dump(data:dict, filepath:str):
|
||||
# Locate or create config file. Read from environment variables to locate file, and if missing or not valid then use default location.
|
||||
configFile = os.getenv('CONFIG') if ((os.getenv('CONFIG').endswith('.yml') or os.getenv('CONFIG').endswith('.yaml')) and not os.getenv('CONFIG').endswith('config_blueprint.yml')) else './data/config.yml'
|
||||
|
||||
if not os.path.exists(configFile):
|
||||
yaml_dump({},configFile)
|
||||
if not os.path.exists(configFile): yaml_dump({},configFile)
|
||||
|
||||
# Locate or create data file. Same as above.
|
||||
dataFile = os.getenv('DATA') if ((os.getenv('DATA').endswith('.yml') or os.getenv('DATA').endswith('.yaml')) and not os.getenv('DATA').endswith('data_blueprint.yml')) else './data/data.yml'
|
||||
|
||||
if not os.path.exists(dataFile):
|
||||
yaml_dump({},dataFile)
|
||||
if not os.path.exists(dataFile): yaml_dump({},dataFile)
|
||||
|
||||
# Locate or create lookup file. Same as above.
|
||||
lookupFile = os.getenv('LOOKUP') if os.getenv('LOOKUP').endswith('.yml') or os.getenv('LOOKUP').endswith('.yaml') else './data/lookup.yml'
|
||||
|
||||
if not os.path.exists(lookupFile):
|
||||
yaml_dump({},lookupFile)
|
||||
if not os.path.exists(lookupFile): yaml_dump({},lookupFile)
|
||||
|
||||
# Locate or create GM lookup file. Same as above.
|
||||
gmFile = os.getenv('GM') if os.getenv('GM').endswith('.yml') or os.getenv('GM').endswith('.yaml') else './data/gm.yml'
|
||||
|
||||
if not os.path.exists(gmFile):
|
||||
yaml_dump({},gmFile)
|
||||
if not os.path.exists(gmFile): yaml_dump({},gmFile)
|
||||
|
||||
# Locate or create Categories lookup file. Same as above.
|
||||
categoriesFile = os.getenv('CATEGORIES') if os.getenv('CATEGORIES').endswith('.yml') or os.getenv('CATEGORIES').endswith('.yaml') else './data/categories.yml'
|
||||
|
||||
if not os.path.exists(categoriesFile):
|
||||
yaml_dump({},categoriesFile)
|
||||
if not os.path.exists(categoriesFile): yaml_dump({},categoriesFile)
|
||||
|
||||
l = [dataFile, lookupFile, gmFile, categoriesFile]
|
||||
# Locate or create Pitches data file. Same as above.
|
||||
pitchesFile = os.getenv('PITCHES') if os.getenv('PITCHES').endswith('.yml') or os.getenv('PITCHES').endswith('.yaml') else './data/pitches.yml'
|
||||
|
||||
if not os.path.exists(pitchesFile): yaml_dump({},pitchesFile)
|
||||
|
||||
l = [dataFile, lookupFile, gmFile, categoriesFile, configFile, pitchesFile]
|
||||
if len(set(l)) != len(l): raise Exception('Config Error: there is a clash between two file names.')
|
||||
|
||||
# Locate Cogs Directory
|
||||
@ -267,6 +267,7 @@ def reloadCogs(cogClass:str = '--all'):
|
||||
|
||||
loadCogs('controlcommands')
|
||||
loadCogs('events')
|
||||
loadCogs('membership')
|
||||
loadCogs('botcommands')
|
||||
loadCogs('slashcommands')
|
||||
if yaml_load(configFile):
|
||||
@ -279,6 +280,8 @@ if yaml_load(configFile):
|
||||
loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
|
||||
loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
|
||||
loadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
|
||||
if yaml_load(pitchesFile):
|
||||
loadCog(f'./{cogsDir}/events/secondary/pitch_listener.py')
|
||||
if any([len(yaml_load(configFile)[x]['membership']) > 0 for x in yaml_load(configFile)]):
|
||||
loadCog(f'./{cogsDir}/slashcommands/secondary/edit_membership.py')
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
import yaml # YAML parser for Bot config files
|
||||
import asyncio # Discord Py Dependency
|
||||
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
|
||||
# logger and handler
|
||||
from bot import configFile, yaml_load, yaml_dump
|
||||
|
||||
#### Error Handler Event Listener for Slash Command Errors
|
||||
class on_slash_command_error(commands.Cog, name='On Command Error'):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_slash_command_error(self, ctx:SlashContext, error):
|
||||
if isinstance(error, Exception):
|
||||
await ctx.send(
|
||||
content='```Invalid Command: {error}```',
|
||||
tts=True,
|
||||
hidden=True,
|
||||
delete_after=10,
|
||||
)
|
||||
# if isinstance(error, commands.CommandNotFound):
|
||||
# print(f'Error: User {ctx.author.name}#{ctx.author.discriminator} / {ctx.author.display_name} entered an invalid command <{ctx.message.clean_content}> in the guild {ctx.guild.name}.')
|
||||
# await ctx.reply(f'```Error: This is not a valid command.```')
|
||||
# elif isinstance(error, commands.CheckFailure):
|
||||
# print(f'Error: User {ctx.author.name}#{ctx.author.discriminator} / {ctx.author.display_name} is not authorised to issue the command <{ctx.command.name}> in the guild {ctx.guild.name}.')
|
||||
# await ctx.reply(f'```Error: You are not authorised to issue this command.```')
|
||||
# else:
|
||||
# print(f'User {ctx.author.name}#{ctx.author.discriminator} / {ctx.author.display_name} received error: "{error}" when attempting to issue command <{ctx.command.name}> in the guild {ctx.guild.name}.')
|
||||
# await ctx.reply(f'```Error: {error}```')
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(on_slash_command_error(client))
|
163
app/cogs/events/secondary/pitch_listener.py
Normal file
163
app/cogs/events/secondary/pitch_listener.py
Normal file
@ -0,0 +1,163 @@
|
||||
import os # OS Locations
|
||||
import yaml # YAML parser for Bot config files
|
||||
import asyncio # Discord Py Dependency
|
||||
import discord # Main Lib
|
||||
from discord.ext import commands # Commands module
|
||||
from discord_slash import SlashCommand, SlashContext, cog_ext, utils, ComponentContext # Slash Command Library
|
||||
from discord_slash.utils.manage_commands import create_choice, create_option, create_permission # Slash Command features
|
||||
from discord_slash.model import SlashCommandPermissionType, ButtonStyle
|
||||
from discord_slash.client import SlashCommand
|
||||
from discord_slash.utils.manage_components import create_select, create_select_option, create_actionrow, wait_for_component, create_button, create_actionrow
|
||||
|
||||
from bot import configFile, yaml_load, yaml_dump, cogsDir, unloadCog, dataFile, lookupFile, gmFile, categoriesFile, pitchesFile, configFile, dataFile, lookupFile, unloadCog
|
||||
|
||||
#### Pitch Command
|
||||
|
||||
class PitchListener(commands.Cog, name='Pitch Listener'):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener(name='on_component')
|
||||
async def _pitch_listener(self, ctx:ComponentContext):
|
||||
conf = yaml_load(configFile)
|
||||
data = yaml_load(dataFile)
|
||||
lookup = yaml_load(lookupFile)
|
||||
pitches = yaml_load(pitchesFile)
|
||||
guildStr = str(ctx.guild.id)
|
||||
if not pitches.get(guildStr, {}): return # If no pitches for current guild, ignore.
|
||||
[timeslot] = [*pitches[guildStr]]
|
||||
if ctx.origin_message.id not in pitches[guildStr][timeslot]['messages'] + [pitches[guildStr][timeslot]['control']]: return # If the context id is not in the pitch menu, ignore
|
||||
newcomer = returning_player = None
|
||||
if 'newcomer' in conf[guildStr]['roles']: newcomer = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['newcomer'], ctx.guild.roles)
|
||||
if 'returning_player' in conf[guildStr]['roles']: returning_player = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['returning_player'], ctx.guild.roles)
|
||||
control = await ctx.channel.fetch_message(pitches[guildStr][timeslot]['control'])
|
||||
header_message = await ctx.channel.fetch_message(pitches[guildStr][timeslot]['header_message'])
|
||||
if ctx.origin_message.id == control.id:
|
||||
if not (set(ctx.author.roles) & set([ctx.guild.get_role(x) for x in conf[str(ctx.guild.id)]['roles']['admin']]) or ctx.author == ctx.guild.owner):
|
||||
await ctx.send(f'```Error: You are not authorised to do this. The control panel may only be issued by an administrator.```',hidden=True)
|
||||
else:
|
||||
if ctx.custom_id == 'allow_returning':
|
||||
await ctx.channel.set_permissions(reason=f'/pitch control switch triggered by {ctx.author.display_name}', target=returning_player, read_messages=True)
|
||||
await ctx.send(f'```Returning Players have now been allowed access to the pitch menu.```', hidden=True)
|
||||
if ctx.custom_id == 'allow_newcomers':
|
||||
await ctx.channel.set_permissions(reason=f'/pitch control switch triggered by {ctx.author.display_name}', target=newcomer, read_messages=True)
|
||||
await ctx.send(f'```Newcomers have now been allowed access to the pitch menu.```', hidden=True)
|
||||
if ctx.custom_id == 'allow_all':
|
||||
await ctx.channel.set_permissions(reason=f'/pitch control switch triggered by {ctx.author.display_name}', target=ctx.guild.default_role, read_messages= True, send_messages=False)
|
||||
await ctx.send(f'```All members have now been allowed access to the pitch menu.```', hidden=True)
|
||||
if ctx.custom_id == 'close_pitches':
|
||||
await ctx.send(f'```Please wait: closing pitches.```', hidden=True)
|
||||
await header_message.delete()
|
||||
for message in pitches[guildStr][timeslot]['messages']:
|
||||
m = await ctx.channel.fetch_message(message)
|
||||
await m.delete()
|
||||
await control.delete()
|
||||
await ctx.channel.edit(reason=f'/pitch command issued by {ctx.author.display_name}', overwrites={})
|
||||
await ctx.channel.send('```Pitch menu cleared. Pitches have now concluded.```')
|
||||
del pitches[guildStr][timeslot]
|
||||
if not pitches[guildStr]: del pitches[guildStr]
|
||||
yaml_dump(pitches,pitchesFile)
|
||||
if not pitches and self.client.get_cog('Pitch Listener') is not None:
|
||||
unloadCog(f'./{cogsDir}/events/secondary/pitch_listener.py')
|
||||
#### Deactivate global pitch listener
|
||||
else:
|
||||
index = int(ctx.custom_id.split('_',1)[1])
|
||||
if ctx.custom_id.startswith('join_'):
|
||||
if set([x.id for x in ctx.author.roles]) & set(pitches[guildStr][timeslot]['roles'].values()):
|
||||
for r in list(set([x.id for x in ctx.author.roles]) & set(pitches[guildStr][timeslot]['roles'].values())):
|
||||
role = ctx.guild.get_role(r)
|
||||
if role.id != pitches[guildStr][timeslot]['roles'][index]:
|
||||
await ctx.author.remove_roles(role,reason=f'/pitch interaction by {ctx.author.display_name}')
|
||||
i = pitches[guildStr][timeslot]['indices'][role.id]
|
||||
element = pitches[guildStr][timeslot]['entries'][i]
|
||||
gm = await self.client.fetch_user(element['gm'])
|
||||
data[guildStr][timeslot][str(role.id)]['current_players'] -= 1
|
||||
element['current_players'] -= 1
|
||||
o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
|
||||
if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
|
||||
if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])} '])
|
||||
if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
|
||||
if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
|
||||
o = ''.join([o,f'```'])
|
||||
spaces_remaining = element["max_players"] - element["current_players"]
|
||||
o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
|
||||
m = await ctx.channel.fetch_message(pitches[guildStr][timeslot]['messages'][i])
|
||||
await m.edit(content=o)
|
||||
tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
|
||||
if tc is None:
|
||||
c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
|
||||
if c is not None:
|
||||
tPos = len(ctx.guild.channels)
|
||||
for t in c.text_channels:
|
||||
if t.position <= tPos:
|
||||
tc = t
|
||||
tPos = t.position
|
||||
if tc is not None:
|
||||
await tc.send(f'```{ctx.author.display_name} has left the game.```')
|
||||
role = ctx.guild.get_role(pitches[guildStr][timeslot]['roles'][index])
|
||||
if role in ctx.author.roles:
|
||||
await ctx.send(f'```Error: You are already in the game `{lookup[guildStr][str(role.id)]["game_title"]}`.```', hidden=True)
|
||||
else:
|
||||
await ctx.author.add_roles(role,reason=f'/pitch interaction by {ctx.author.display_name}')
|
||||
element = pitches[guildStr][timeslot]['entries'][index]
|
||||
data[guildStr][timeslot][str(role.id)]['current_players'] += 1
|
||||
element['current_players'] += 1
|
||||
gm = await self.client.fetch_user(element['gm'])
|
||||
o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
|
||||
if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
|
||||
if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])} '])
|
||||
if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
|
||||
if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
|
||||
o = ''.join([o,f'```'])
|
||||
spaces_remaining = element["max_players"] - element["current_players"]
|
||||
o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
|
||||
m = await ctx.channel.fetch_message(pitches[guildStr][timeslot]['messages'][index])
|
||||
await m.edit(content=o)
|
||||
await ctx.send(f'You have joined the game `{lookup[guildStr][str(role.id)]["game_title"]}`.',hidden=True)
|
||||
tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
|
||||
if tc is None:
|
||||
c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
|
||||
if c is not None:
|
||||
tPos = len(ctx.guild.channels)
|
||||
for t in c.text_channels:
|
||||
if t.position <= tPos:
|
||||
tc = t
|
||||
tPos = t.position
|
||||
if tc is not None:
|
||||
await tc.send(f'```{ctx.author.display_name} has joined the game.```')
|
||||
elif ctx.custom_id.startswith('leave_'):
|
||||
role = ctx.guild.get_role(pitches[guildStr][timeslot]['roles'][index])
|
||||
if role not in ctx.author.roles:
|
||||
await ctx.send(f'```Error: You are not in the game `{lookup[guildStr][str(role.id)]["game_title"]}`.```', hidden=True)
|
||||
else:
|
||||
await ctx.author.remove_roles(role,reason=f'/pitch interaction by {ctx.author.display_name}')
|
||||
data[guildStr][timeslot][str(role.id)]['current_players'] -= 1
|
||||
element = pitches[guildStr][timeslot]['entries'][index]
|
||||
gm = await self.client.fetch_user(element['gm'])
|
||||
o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
|
||||
if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
|
||||
if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])} '])
|
||||
if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
|
||||
if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
|
||||
o = ''.join([o,f'```'])
|
||||
spaces_remaining = element["max_players"] - element["current_players"]
|
||||
o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
|
||||
me = await ctx.channel.fetch_message(pitches[guildStr][timeslot]['messages'][index])
|
||||
await me.edit(content=o)
|
||||
await ctx.send(f'You have left the game `{lookup[guildStr][str(role.id)]["game_title"]}`.',hidden=True)
|
||||
tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
|
||||
if tc is None:
|
||||
c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
|
||||
if c is not None:
|
||||
tPos = len(ctx.guild.channels)
|
||||
for t in c.text_channels:
|
||||
if t.position <= tPos:
|
||||
tc = t
|
||||
tPos = t.position
|
||||
if tc is not None:
|
||||
await tc.send(f'```{ctx.author.display_name} has left the game.```')
|
||||
yaml_dump(data, dataFile)
|
||||
yaml_dump(pitches, pitchesFile)
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(PitchListener(client))
|
@ -3,8 +3,9 @@ import yaml # YAML parser for Bot config files
|
||||
import asyncio # Discord Py Dependency
|
||||
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_components import create_select, create_select_option, create_actionrow, wait_for_component, create_button, create_actionrow, create_choice, create_option
|
||||
from discord_slash import SlashCommand, SlashContext, cog_ext, utils, ComponentContext # Slash Command Library
|
||||
from discord_slash.utils.manage_components import create_select, create_select_option, create_actionrow, wait_for_component, create_button, create_actionrow
|
||||
from discord_slash.utils.manage_commands import create_choice, create_option
|
||||
from discord_slash.model import ButtonStyle
|
||||
import logging
|
||||
# logger and handler
|
||||
@ -16,16 +17,17 @@ class MemberVerification(commands.Cog, name='Member Verification Cog'):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
@commands.Cog.listener(name='on_message')
|
||||
async def _submission_listener(self, message):
|
||||
conf = yaml_load(configFile)
|
||||
categories = yaml_load(categoriesFile)
|
||||
guildStr = str(message.guild.id)
|
||||
lookup = yaml_load(lookupFile)
|
||||
if conf[guildStr]['channels'].get('signup', None) is not None: return
|
||||
if conf[guildStr]['channels'].get('signup', None) is None: return
|
||||
if message.author.bot: return
|
||||
if message.channel.id != conf[guildStr]['channels']['signup']: return
|
||||
if not message.attachments:
|
||||
await message.author.send(f'```Error: The message you posted in the `{message.channel.name}` channel of the guild `{message.guild.name}` was invalid. Your post must contain a screensot of your proof of purchase for membership.```')
|
||||
if not (message.attachments):
|
||||
await message.channel.send(f'```Error: The message you posted in the `{message.channel.name}` channel of the guild `{message.guild.name}` was invalid. Your post must contain a screensot of your proof of purchase for membership.```')
|
||||
await message.delete()
|
||||
return
|
||||
membership = [discord.utils.get(message.guild.roles, id=x) for x in conf[guildStr]['membership']]
|
||||
@ -35,9 +37,9 @@ class MemberVerification(commands.Cog, name='Member Verification Cog'):
|
||||
admin_buttons.append(create_button(style=ButtonStyle.grey, label='Alert', emoji='⚠️', custom_id=f'alert_{message.id}'))
|
||||
admin_buttons.append(create_button(style=ButtonStyle.red, label='Deny', emoji='✖️', custom_id=f'deny_{message.id}'))
|
||||
admin_buttons.append(create_button(style=ButtonStyle.green, label='Done', emoji='▶️', custom_id=f'done_{message.id}'))
|
||||
o = f'```For Administrators: Please verify the membership request submitted.```\n'
|
||||
o = f'```For Administrators: Please verify the membership request submitted by `{message.author.display_name}`.```'
|
||||
admins = '|'.join([discord.utils.get(message.guild.roles, id=x).mention for x in conf[guildStr]['roles']['admin']])
|
||||
o = '\n'.join((o,admins))
|
||||
o = ''.join((admins,o))
|
||||
m = await message.reply(
|
||||
content= o,
|
||||
components=[
|
||||
@ -55,55 +57,70 @@ class MemberVerification(commands.Cog, name='Member Verification Cog'):
|
||||
)
|
||||
]
|
||||
)
|
||||
while True:
|
||||
interaction_ctx = await wait_for_component(self.client, messages=m)
|
||||
if not (set(interaction_ctx.author.roles) & set([interaction_ctx.guild.get_role(x) for x in conf[str(interaction_ctx.guild.id)]['roles']['admin']]) or interaction_ctx.author == interaction_ctx.guild.owner):
|
||||
await interaction_ctx.send(f'```Error: You are not authorised to assign memberships for guild `{interaction_ctx.guild.name}`. Only administrators may assign memberships using this interface.```', hidden=True)
|
||||
else:
|
||||
submission = await interaction_ctx.channel.fetch_message(int(interaction_ctx.custom_id.split('_',1)[1]))
|
||||
if interaction_ctx.custom_id.startswith('done_'):
|
||||
await interaction_ctx.send(f'```Membership verification complete.```', hidden=True)
|
||||
break
|
||||
elif interaction_ctx.custom_id.startswith('deny_'):
|
||||
await interaction_ctx.send(f'```Membership verification denied.```', hidden=True)
|
||||
embed = discord.Embed(
|
||||
title = submission.author.name,
|
||||
description = f'[Jup to Message]({submission.jump_url})',
|
||||
colour = discord.Colour.red(),
|
||||
)
|
||||
await submission.author.send(f'```Your membership for guild `{submission.guild.name}` could not be verified. Please make sure your name and the kind of membership that you have bought are visible in the screenshot you upload. Please contact a Committee member if you have any difficulties.```')
|
||||
if conf[guildStr]['channels'].get('mod', None) is not None:
|
||||
await submission.guild.get_channel(conf[guildStr]['channels']['mod']).send(f'```Verifying the membership of {submission.author.display_name} failed.```\n{admins}', embed=embed)
|
||||
break
|
||||
elif interaction_ctx.custom_id.startswith('alert_'):
|
||||
await interaction_ctx.send(f'```Membership verification alert raised.```', hidden=True)
|
||||
embed = discord.Embed(
|
||||
title = submission.author.name,
|
||||
description = f'[Jup to Message]({submission.jump_url})',
|
||||
colour = discord.Colour.orange()
|
||||
)
|
||||
await submission.author.send(f'```Your membership for guild `{submission.guild.name}` needs to be reviewed by a Committee member.```')
|
||||
if conf[guildStr]['channels'].get('mod', None) is not None:
|
||||
await submission.guild.get_channel(conf[guildStr]['channels']['mod']).send(f'```There is a problem verifying the membership of {submission.author.display_name}.\nCould someone verify this person\'s membership manually via the EUSA portal?.```\n{admins}', embed=embed)
|
||||
elif interaction_ctx.custom_id.startswith('student_'):
|
||||
await interaction_ctx.send(f'````Student` role granted.```', hidden=True)
|
||||
student_role = submission.guild.get_role(conf[guildStr]['roles']['student'])
|
||||
await submission.author.add_roles(student_role, reason=f'Membership Verification: Student role assigned by `{interaction_ctx.author.display_name}`.')
|
||||
await submission.author.send(f'```You have additionally been assigned the role `Student` in the guild `{submission.guild.name}`.```')
|
||||
elif interaction_ctx.custom_id.startswith('membership_'):
|
||||
[selected_membership] = interaction_ctx.selected_options
|
||||
selected_role = interaction_ctx.guild.get_role(int(selected_membership))
|
||||
if selected_role not in submission.author.roles:
|
||||
await interaction_ctx.send(f'```Membership `{selected_role.name}` added to member `{submission.author.display_name}`.```', hidden=True)
|
||||
await submission.author.add_roles(selected_role, reason=f'Membership Verification: Membership verified by `{interaction_ctx.author.display_name}`.')
|
||||
await submission.author.send(f'```Your membership for guild `{submission.guild.name}` has been verified and you have been assigned the role `{selected_role.name}`.```')
|
||||
else:
|
||||
await interaction_ctx.send(f'```Membership `{selected_role.name}` removed from member `{submission.author.display_name}`.```', hidden=True)
|
||||
await submission.author.remove_roles(selected_role, reason=f'Membership Verification: Membership removed by `{interaction_ctx.author.display_name}`.')
|
||||
await submission.author.send(f'```Your role `{selected_role.name}` has been removed in the guild `{submission.guild.name}`.```')
|
||||
if conf[guildStr]['notifications'].get('signup', False):
|
||||
embed = discord.Embed(
|
||||
title = f'Member Verification Request',
|
||||
description = f'User: {message.author.name}\n\n[Jup to Message]({m.jump_url})',
|
||||
colour = discord.Colour.blue(),
|
||||
)
|
||||
if conf[guildStr]['channels'].get('mod', None) is not None:
|
||||
await message.guild.get_channel(conf[guildStr]['channels']['mod']).send(f'```New membership verification request.```\n{admins}', embed=embed)
|
||||
|
||||
|
||||
@commands.Cog.listener(name='on_component')
|
||||
async def _verification_response(self, ctx:ComponentContext):
|
||||
conf = yaml_load(configFile)
|
||||
categories = yaml_load(categoriesFile)
|
||||
guildStr = str(ctx.guild.id)
|
||||
admins = '|'.join([discord.utils.get(ctx.guild.roles, id=x).mention for x in conf[guildStr]['roles']['admin']])
|
||||
lookup = yaml_load(lookupFile)
|
||||
if ctx.channel.id != conf[guildStr]['channels']['signup']: return
|
||||
if not (set(ctx.author.roles) & set([ctx.guild.get_role(x) for x in conf[str(ctx.guild.id)]['roles']['admin']]) or ctx.author == ctx.guild.owner):
|
||||
await ctx.send(f'```Error: You are not authorised to assign memberships for guild `{ctx.guild.name}`. Only administrators may assign memberships using this interface.```', hidden=True)
|
||||
else:
|
||||
submission = await ctx.channel.fetch_message(int(ctx.custom_id.split('_',1)[1]))
|
||||
if ctx.custom_id.startswith('done_'):
|
||||
await ctx.send(f'```Membership verification complete.```', hidden=True)
|
||||
await ctx.origin_message.delete()
|
||||
elif ctx.custom_id.startswith('deny_'):
|
||||
await ctx.send(f'```Membership verification denied.```', hidden=True)
|
||||
embed = discord.Embed(
|
||||
title = submission.author.name,
|
||||
description = f'[Jup to Message]({submission.jump_url})',
|
||||
colour = discord.Colour.red(),
|
||||
)
|
||||
await submission.channel.send(f'```Your membership for guild `{submission.guild.name}` could not be verified. Please make sure your name and the kind of membership that you have bought are visible in the screenshot you upload. Please contact a Committee member if you have any difficulties.```')
|
||||
if conf[guildStr]['channels'].get('mod', None) is not None:
|
||||
await submission.guild.get_channel(conf[guildStr]['channels']['mod']).send(f'```Verifying the membership of {submission.author.display_name} failed.```\n{admins}', embed=embed)
|
||||
await ctx.origin_message.delete()
|
||||
elif ctx.custom_id.startswith('alert_'):
|
||||
await ctx.send(f'```Membership verification alert raised.```', hidden=True)
|
||||
embed = discord.Embed(
|
||||
title = submission.author.name,
|
||||
description = f'[Jup to Message]({submission.jump_url})',
|
||||
colour = discord.Colour.orange()
|
||||
)
|
||||
await submission.channel.send(f'```Your membership for guild `{submission.guild.name}` needs to be reviewed by a Committee member.```')
|
||||
if conf[guildStr]['channels'].get('mod', None) is not None:
|
||||
await submission.guild.get_channel(conf[guildStr]['channels']['mod']).send(f'```There is a problem verifying the membership of {submission.author.display_name}.\nCould someone verify this person\'s membership manually via the EUSA portal?.```\n{admins}', embed=embed)
|
||||
elif ctx.custom_id.startswith('student_'):
|
||||
await ctx.send(f'````Student` role granted.```', hidden=True)
|
||||
student_role = submission.guild.get_role(conf[guildStr]['roles']['student'])
|
||||
await submission.author.add_roles(student_role, reason=f'Membership Verification: Student role assigned by `{ctx.author.display_name}`.')
|
||||
await submission.channel.send(f'```You have additionally been assigned the role `Student` in the guild `{submission.guild.name}`.```')
|
||||
elif ctx.custom_id.startswith('membership_'):
|
||||
[selected_membership] = ctx.selected_options
|
||||
selected_role = ctx.guild.get_role(int(selected_membership))
|
||||
if selected_role not in submission.author.roles:
|
||||
await ctx.send(f'```Membership `{selected_role.name}` added to member `{submission.author.display_name}`.```', hidden=True)
|
||||
await submission.author.add_roles(selected_role, reason=f'Membership Verification: Membership verified by `{ctx.author.display_name}`.')
|
||||
await submission.channel.send(f'```Your membership for guild `{submission.guild.name}` has been verified and you have been assigned the role `{selected_role.name}`.```')
|
||||
else:
|
||||
pass
|
||||
await m.delete()
|
||||
await ctx.send(f'```Membership `{selected_role.name}` removed from member `{submission.author.display_name}`.```', hidden=True)
|
||||
await submission.author.remove_roles(selected_role, reason=f'Membership Verification: Membership removed by `{ctx.author.display_name}`.')
|
||||
await submission.channel.send(f'```Your role `{selected_role.name}` has been removed in the guild `{submission.guild.name}`.```')
|
||||
else:
|
||||
pass
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(MemberVerification(client))
|
@ -15,15 +15,15 @@ class RestrictionListener(commands.Cog, name='Membership Restriction Listener'):
|
||||
self.client = client
|
||||
|
||||
# Block non-verified user from posting messages.
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self,message):
|
||||
@commands.Cog.listener(name='on_message')
|
||||
async def _restriction_listener(self,message):
|
||||
conf = yaml_load(configFile)
|
||||
categories = yaml_load(categoriesFile)
|
||||
guildStr = str(message.guild.id)
|
||||
lookup = yaml_load(lookupFile)
|
||||
if conf[guildStr].get('restrict',False): return
|
||||
if not conf[guildStr].get('restrict',False): return
|
||||
if message.author.bot: return
|
||||
if str(message.channel.category) not in categories[guildStr]: return
|
||||
if str(message.channel.category) in categories[guildStr]: return
|
||||
if (set(message.author.roles) & set([message.guild.get_role(x) for x in conf[guildStr]['roles']['admin']]) or message.author == message.guild.owner): return
|
||||
if set(message.author.roles) & set([message.guild.get_role(x) for x in conf[guildStr]['membership']]): return
|
||||
if message.channel.overwrites_for(message.author).manage_channels: return
|
||||
@ -33,18 +33,21 @@ class RestrictionListener(commands.Cog, name='Membership Restriction Listener'):
|
||||
await message.delete()
|
||||
|
||||
# Reinstate on verification
|
||||
@commands.Cog.listener()
|
||||
async def on_member_update(self, before, after):
|
||||
@commands.Cog.listener(name='on_member_update')
|
||||
async def _reinstate_listener(self, before, after):
|
||||
if before.roles == after.roles: return
|
||||
if len(set(after.roles) - set(before.roles)) != 1: return
|
||||
[d] = list(set(after.roles) - set(before.roles))
|
||||
conf = yaml_load(configFile)
|
||||
categories = yaml_load(categoriesFile)
|
||||
guildStr = str(after.guild.id)
|
||||
if d.id not in conf[guildStr]['membership']: return
|
||||
lookup = yaml_load(lookupFile)
|
||||
if not set(after.author.roles) & set([after.guild.get_role(x) for x in conf[guildStr]['membership']]): return
|
||||
for game in list(set(after.author.roles) & set([after.guild.get_role(int(x)) for x in lookup[guildStr]])):
|
||||
c = discord.utils.get(lambda x: x.id == lookup[guildStr][str(game.id)]['category'])
|
||||
if not set(after.roles) & set([after.guild.get_role(x) for x in conf[guildStr]['membership']]): return
|
||||
for game in list(set(after.roles) & set([after.guild.get_role(int(x)) for x in lookup[guildStr]])):
|
||||
c = discord.utils.get(after.guild.categories, id=lookup[guildStr][str(game.id)]['category'])
|
||||
if c is not None:
|
||||
if c.overwrites_for(after).send_messages is False: await c.set_permissions(after, overwrite = False, reason= f'Membership Restriction: {after.display_name} has been verified and reinstated.')
|
||||
if c.overwrites_for(after).send_messages is False: await c.set_permissions(after, overwrite = None, reason= f'Membership Restriction: {after.display_name} has been verified and reinstated.')
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(RestrictionListener(client))
|
@ -9,7 +9,7 @@ from discord_slash.model import SlashCommandPermissionType, ButtonStyle
|
||||
from discord_slash.client import SlashCommand
|
||||
from discord_slash.utils.manage_components import create_select, create_select_option, create_actionrow, wait_for_component, create_button, create_actionrow
|
||||
|
||||
from bot import configFile, yaml_load, yaml_dump, cogsDir, unloadCog, dataFile, lookupFile, gmFile, categoriesFile
|
||||
from bot import configFile, yaml_load, yaml_dump, cogsDir, unloadCog, dataFile, lookupFile, gmFile, categoriesFile, pitchesFile, loadCog
|
||||
|
||||
#### Pitch Command
|
||||
|
||||
@ -42,8 +42,12 @@ class Pitch(commands.Cog, name='Pitch Command'):
|
||||
lookup = yaml_load(lookupFile)
|
||||
gms = yaml_load(gmFile)
|
||||
categories = yaml_load(categoriesFile)
|
||||
pitches = {}
|
||||
guildStr = str(ctx.guild.id)
|
||||
pitches = yaml_load(pitchesFile)
|
||||
if guildStr not in pitches: pitches[guildStr] = {}
|
||||
if pitches[guildStr]:
|
||||
await ctx.send(f'```Error: pitches are already running for the guild `{ctx.guild.name}`. Please close the existing pitches first before issuing this command.```')
|
||||
return
|
||||
if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {}
|
||||
tsDict = {k: conf[guildStr]['timeslots'][k] for k in data[guildStr] if data[guildStr][k]}
|
||||
optionsList = [create_select_option(label=tsDict[x], value=x, description=x) for x in tsDict]
|
||||
@ -83,7 +87,6 @@ class Pitch(commands.Cog, name='Pitch Command'):
|
||||
ctx.guild.default_role: p
|
||||
}
|
||||
)
|
||||
if guildStr not in pitches: pitches[guildStr] = {}
|
||||
if timeslot not in pitches[guildStr]: pitches[guildStr][timeslot] = {}
|
||||
pitches[guildStr][timeslot]['indices'] = {}
|
||||
pitches[guildStr][timeslot]['entries'] = [x for x in data[guildStr][timeslot].values()]
|
||||
@ -91,6 +94,7 @@ class Pitch(commands.Cog, name='Pitch Command'):
|
||||
header_message = await ctx.channel.send(
|
||||
content=f'**Game listing for {conf[guildStr]["timeslots"][timeslot]}**\n_ _```The following are the games that are being pitched. Please select which game you would like to join by clicking on the `Join` button below.```'
|
||||
)
|
||||
pitches[guildStr][timeslot]['header_message'] = header_message.id
|
||||
pitches[guildStr][timeslot]['messages'] = []
|
||||
pitches[guildStr][timeslot]['roles'] = {}
|
||||
for index, element in enumerate(pitches[guildStr][timeslot]['entries']):
|
||||
@ -122,9 +126,9 @@ class Pitch(commands.Cog, name='Pitch Command'):
|
||||
)
|
||||
]
|
||||
)
|
||||
pitches[guildStr][timeslot]['messages'].append(m)
|
||||
pitches[guildStr][timeslot]['messages'].append(m.id)
|
||||
r = discord.utils.find(lambda x: x.id == element['role'],ctx.guild.roles)
|
||||
pitches[guildStr][timeslot]['roles'][index] = r
|
||||
pitches[guildStr][timeslot]['roles'][index] = r.id
|
||||
pitches[guildStr][timeslot]['indices'][r.id] = index
|
||||
newcomer = returning_player = None
|
||||
if 'newcomer' in conf[guildStr]['roles']: newcomer = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['newcomer'], ctx.guild.roles)
|
||||
@ -172,123 +176,11 @@ class Pitch(commands.Cog, name='Pitch Command'):
|
||||
)
|
||||
]
|
||||
)
|
||||
while True:
|
||||
button_ctx = await wait_for_component(
|
||||
self.client,
|
||||
messages=pitches[guildStr][timeslot]['messages'] + [control]
|
||||
)
|
||||
if button_ctx.origin_message.id == control.id:
|
||||
if not (set(ctx.author.roles) & set([ctx.guild.get_role(x) for x in conf[str(ctx.guild.id)]['roles']['admin']]) or ctx.author == ctx.guild.owner):
|
||||
await button_ctx.send(f'```Error: You are not authorised to do this. The control panel may only be issued by an administrator.```',hidden=True)
|
||||
else:
|
||||
if button_ctx.custom_id == 'allow_returning':
|
||||
await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=returning_player, read_messages=True)
|
||||
await button_ctx.send(f'```Returning Players have now been allowed access to the pitch menu.```', hidden=True)
|
||||
if button_ctx.custom_id == 'allow_newcomers':
|
||||
await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=newcomer, read_messages=True)
|
||||
await button_ctx.send(f'```Newcomers have now been allowed access to the pitch menu.```', hidden=True)
|
||||
if button_ctx.custom_id == 'allow_all':
|
||||
await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=ctx.guild.default_role, read_messages= True, send_messages=False)
|
||||
await button_ctx.send(f'```All members have now been allowed access to the pitch menu.```', hidden=True)
|
||||
if button_ctx.custom_id == 'close_pitches': break
|
||||
else:
|
||||
index = int(button_ctx.custom_id.split('_',1)[1])
|
||||
if button_ctx.custom_id.startswith('join_'):
|
||||
if set(button_ctx.author.roles) & set(pitches[guildStr][timeslot]['roles'].values()):
|
||||
print('Check 0')
|
||||
for role in list(set(button_ctx.author.roles) & set(pitches[guildStr][timeslot]['roles'].values())):
|
||||
if role != pitches[guildStr][timeslot]['roles'][index]:
|
||||
print('check 1')
|
||||
await button_ctx.author.remove_roles(role,reason=f'/pitch interaction by {button_ctx.author.display_name}')
|
||||
data[guildStr][timeslot][str(role.id)]['current_players'] -= 1
|
||||
i = pitches[guildStr][timeslot]['indices'][role.id]
|
||||
element = pitches[guildStr][timeslot]['entries'][i]
|
||||
gm = await self.client.fetch_user(element['gm'])
|
||||
o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
|
||||
if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
|
||||
if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])} '])
|
||||
if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
|
||||
if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
|
||||
o = ''.join([o,f'```'])
|
||||
spaces_remaining = element["max_players"] - element["current_players"]
|
||||
o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
|
||||
await pitches[guildStr][timeslot]['messages'][i].edit(content=o)
|
||||
tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
|
||||
if tc is None:
|
||||
c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
|
||||
if c is not None:
|
||||
tPos = len(ctx.guild.channels)
|
||||
for t in c.text_channels:
|
||||
if t.position <= tPos:
|
||||
tc = t
|
||||
tPos = t.position
|
||||
if tc is not None:
|
||||
await tc.send(f'```{button_ctx.author.display_name} has left the game.```')
|
||||
role = pitches[guildStr][timeslot]['roles'][index]
|
||||
if role in button_ctx.author.roles:
|
||||
await button_ctx.send(f'```Error: You are already in the game `{lookup[guildStr][str(role.id)]["game_title"]}`.```', hidden=True)
|
||||
else:
|
||||
await button_ctx.author.add_roles(role,reason=f'/pitch interaction by {button_ctx.author.display_name}')
|
||||
data[guildStr][timeslot][str(role.id)]['current_players'] += 1
|
||||
element = pitches[guildStr][timeslot]['entries'][index]
|
||||
gm = await self.client.fetch_user(element['gm'])
|
||||
o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
|
||||
if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
|
||||
if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])} '])
|
||||
if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
|
||||
if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
|
||||
o = ''.join([o,f'```'])
|
||||
spaces_remaining = element["max_players"] - element["current_players"]
|
||||
o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
|
||||
await pitches[guildStr][timeslot]['messages'][index].edit(content=o)
|
||||
await button_ctx.send(f'You have joined the game `{lookup[guildStr][str(role.id)]["game_title"]}`.',hidden=True)
|
||||
tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
|
||||
if tc is None:
|
||||
c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
|
||||
if c is not None:
|
||||
tPos = len(ctx.guild.channels)
|
||||
for t in c.text_channels:
|
||||
if t.position <= tPos:
|
||||
tc = t
|
||||
tPos = t.position
|
||||
if tc is not None:
|
||||
await tc.send(f'```{button_ctx.author.display_name} has joined the game.```')
|
||||
elif button_ctx.custom_id.startswith('leave_'):
|
||||
role = pitches[guildStr][timeslot]['roles'][index]
|
||||
if role not in button_ctx.author.roles:
|
||||
await button_ctx.send(f'```Error: You are not in the game `{lookup[guildStr][str(role.id)]["game_title"]}`.```', hidden=True)
|
||||
else:
|
||||
await button_ctx.author.remove_roles(role,reason=f'/pitch interaction by {button_ctx.author.display_name}')
|
||||
data[guildStr][timeslot][str(role.id)]['current_players'] -= 1
|
||||
element = pitches[guildStr][timeslot]['entries'][index]
|
||||
gm = await self.client.fetch_user(element['gm'])
|
||||
o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
|
||||
if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
|
||||
if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])} '])
|
||||
if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
|
||||
if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
|
||||
o = ''.join([o,f'```'])
|
||||
spaces_remaining = element["max_players"] - element["current_players"]
|
||||
o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
|
||||
await pitches[guildStr][timeslot]['messages'][index].edit(content=o)
|
||||
await button_ctx.send(f'You have left the game `{lookup[guildStr][str(role.id)]["game_title"]}`.',hidden=True)
|
||||
tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
|
||||
if tc is None:
|
||||
c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
|
||||
if c is not None:
|
||||
tPos = len(ctx.guild.channels)
|
||||
for t in c.text_channels:
|
||||
if t.position <= tPos:
|
||||
tc = t
|
||||
tPos = t.position
|
||||
if tc is not None:
|
||||
await tc.send(f'```{button_ctx.author.display_name} has left the game.```')
|
||||
yaml_dump(data, dataFile)
|
||||
await header_message.delete()
|
||||
for message in pitches[guildStr][timeslot]['messages']: await message.delete()
|
||||
await control.delete()
|
||||
await ctx.channel.edit(reason=f'/pitch command issued by {ctx.author.display_name}', overwrites={})
|
||||
await button_ctx.channel.send('```Pitch menu cleared. Pitches have now concluded.```')
|
||||
pitches[guildStr][timeslot]['control'] = control.id
|
||||
yaml_dump(pitches,pitchesFile)
|
||||
if self.client.get_cog('Pitch Listener') is None:
|
||||
loadCog(f'./{cogsDir}/events/secondary/pitch_listener.py')
|
||||
#### Activate global pitch listener
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Pitch(client))
|
@ -1 +1,4 @@
|
||||
'864651943820525609': {}
|
||||
'864651943820525609':
|
||||
'868506573700468787': 868506572421234718
|
||||
'868506638720577586': 868506637252583494
|
||||
'868506722187227166': 868506720375300137
|
||||
|
@ -2,7 +2,7 @@
|
||||
channels:
|
||||
help: 866645822472454206
|
||||
mod: 865348933022515220
|
||||
signup: 866110421592965171
|
||||
signup: 868523157680693278
|
||||
configured: true
|
||||
membership:
|
||||
- 866795009121714207
|
||||
@ -12,6 +12,7 @@
|
||||
signup: true
|
||||
owner: 493694762210033664
|
||||
prefix: '-'
|
||||
restrict: false
|
||||
roles:
|
||||
admin:
|
||||
- 866642278529368095
|
||||
|
@ -1 +1,38 @@
|
||||
'864651943820525609': {}
|
||||
'864651943820525609':
|
||||
avatar:
|
||||
'868506572421234718':
|
||||
category: 868506573700468787
|
||||
current_players: 1
|
||||
game_title: Kyoshi
|
||||
gm: 864649599671205914
|
||||
header_message: 868506578934976543
|
||||
max_players: 5
|
||||
min_players: null
|
||||
platform: null
|
||||
role: 868506572421234718
|
||||
system: null
|
||||
text_channel: 868506576695230534
|
||||
'868506637252583494':
|
||||
category: 868506638720577586
|
||||
current_players: 0
|
||||
game_title: Roku
|
||||
gm: 864649599671205914
|
||||
header_message: 868506642545795142
|
||||
max_players: 5
|
||||
min_players: null
|
||||
platform: null
|
||||
role: 868506637252583494
|
||||
system: null
|
||||
text_channel: 868506640347971655
|
||||
'868506720375300137':
|
||||
category: 868506722187227166
|
||||
current_players: 0
|
||||
game_title: Aang
|
||||
gm: 864649599671205914
|
||||
header_message: 868506726029197312
|
||||
max_players: 5
|
||||
min_players: null
|
||||
platform: null
|
||||
role: 868506720375300137
|
||||
system: null
|
||||
text_channel: 868506724045303878
|
||||
|
@ -1 +1,5 @@
|
||||
'864651943820525609': {}
|
||||
'864651943820525609':
|
||||
'864649599671205914':
|
||||
- 868506572421234718
|
||||
- 868506637252583494
|
||||
- 868506720375300137
|
||||
|
@ -1 +1,19 @@
|
||||
'864651943820525609': {}
|
||||
'864651943820525609':
|
||||
'868506572421234718':
|
||||
category: 868506573700468787
|
||||
game_title: Kyoshi
|
||||
gm: 864649599671205914
|
||||
text_channel: 868506576695230534
|
||||
time: avatar
|
||||
'868506637252583494':
|
||||
category: 868506638720577586
|
||||
game_title: Roku
|
||||
gm: 864649599671205914
|
||||
text_channel: 868506640347971655
|
||||
time: avatar
|
||||
'868506720375300137':
|
||||
category: 868506722187227166
|
||||
game_title: Aang
|
||||
gm: 864649599671205914
|
||||
text_channel: 868506724045303878
|
||||
time: avatar
|
||||
|
1
app/data/pitches.yml
Normal file
1
app/data/pitches.yml
Normal file
@ -0,0 +1 @@
|
||||
{}
|
Loading…
Reference in New Issue
Block a user