forked from viveksantayana/geas-bot
Debugged membership sign-ups and pitch menu.
Ready for more rigorous testing.
This commit is contained in:
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 @@
|
||||
{}
|
Reference in New Issue
Block a user