Debugged membership sign-ups and pitch menu.

Ready for more rigorous testing.
This commit is contained in:
2021-07-24 17:58:23 +01:00
parent 173aeb2a3c
commit e30e89e7e3
13 changed files with 356 additions and 245 deletions

View File

@ -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')

View File

@ -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))

View 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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -1 +1,4 @@
'864651943820525609': {}
'864651943820525609':
'868506573700468787': 868506572421234718
'868506638720577586': 868506637252583494
'868506722187227166': 868506720375300137

View File

@ -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

View File

@ -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

View File

@ -1 +1,5 @@
'864651943820525609': {}
'864651943820525609':
'864649599671205914':
- 868506572421234718
- 868506637252583494
- 868506720375300137

View File

@ -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
View File

@ -0,0 +1 @@
{}