From 94ce0aa31a482f9efd187c02585f0b3a23d43ab0 Mon Sep 17 00:00:00 2001 From: Vivek Santayana Date: Thu, 5 Aug 2021 02:00:03 +0100 Subject: [PATCH] Fully implemented /tcard command. Bug fixes for member signup Added live update of game header message during pitches Documentation updates --- COMMANDS.md | 6 ++ README.md | 3 +- app/cogs/events/secondary/pitch_listener.py | 58 ++++++++++++++----- app/cogs/membership/member_verification.py | 18 +++--- .../secondary/player_commands.py | 4 +- app/cogs/slashcommands/secondary/tcard.py | 6 +- 6 files changed, 62 insertions(+), 33 deletions(-) diff --git a/COMMANDS.md b/COMMANDS.md index ea1d80c..523a081 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -71,6 +71,12 @@ These commands are locked until there is at least one game configured. | `/player leave` | Removes the user issuing the command from the game they are in. This command `must be issued in a text channel associated with the game you are trying to leave`. | | `/player remove <@player>` | Removes the user mentioned from the game. This command `must be issued in a text channel associated with the game you are trying to leave`. | +While this is not strictly a `/player` command, and it is housed in a separate cog, it has the same level of permissions and prerequisites as all the `/player` commands. + +| Command | Description | +|---|---| +|`/tcard`| Invokes a T-Card in the game. This command also posts a graphic of the T-Card, tags the game's role, and pings a message in the appropriate voice channel.| + ### Pitch Command The `/pitch` command is used to run pitches for games on the server. diff --git a/README.md b/README.md index 8f1b1b6..2871f00 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,8 @@ in order for to authenticate as the correct bot. | | |-- game_management.py | | |-- manipulate_timeslots.py | | |-- pitch.py -| | `-- player_commands.py +| | |-- player_commands.py +| | `-- tcard.py | |-- data | | |-- .gitkeep | | |-- categories.yml diff --git a/app/cogs/events/secondary/pitch_listener.py b/app/cogs/events/secondary/pitch_listener.py index 4dba14f..ab90ced 100644 --- a/app/cogs/events/secondary/pitch_listener.py +++ b/app/cogs/events/secondary/pitch_listener.py @@ -66,13 +66,14 @@ class PitchListener(commands.Cog, name='Pitch Listener'): 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) + rStr = str(role.id) 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']) - if ctx.author.id != lookup[guildStr][str(role.id)]['gm']: - data[guildStr][timeslot][str(role.id)]['current_players'] -= 1 + if ctx.author.id != lookup[guildStr][rStr]['gm']: + data[guildStr][timeslot][rStr]['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']) @@ -84,9 +85,9 @@ class PitchListener(commands.Cog, name='Pitch Listener'): 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) + tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['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) + c = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['category'],ctx.guild.categories) if c is not None: tPos = len(ctx.guild.channels) for t in c.text_channels: @@ -96,13 +97,15 @@ class PitchListener(commands.Cog, name='Pitch Listener'): 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]) + rStr = str(role.id) 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) + await ctx.send(f'```Error: You are already in the game `{lookup[guildStr][rStr]["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 + if ctx.author.id != lookup[guildStr][rStr]['gm']: + data[guildStr][timeslot][rStr]['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']) @@ -114,10 +117,10 @@ class PitchListener(commands.Cog, name='Pitch Listener'): 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) + await ctx.send(f'You have joined the game `{lookup[guildStr][rStr]["game_title"]}`.',hidden=True) + tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['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) + c = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['category'],ctx.guild.categories) if c is not None: tPos = len(ctx.guild.channels) for t in c.text_channels: @@ -126,15 +129,27 @@ class PitchListener(commands.Cog, name='Pitch Listener'): tPos = t.position if tc is not None: await tc.send(f'```{ctx.author.display_name} has joined the game.```') + ts = lookup[guildStr][rStr]['time'] + p = await tc.pins() + if p is not None: + header = discord.utils.find(lambda x: x.id == data[guildStr][ts][rStr]['header_message'], p) + if header is not None: + text = header.content.split('\n') + for line, item in enumerate(text): + if 'Current Players: ' in item: + text[line] = f'Current Players: {str(data[guildStr][ts][rStr]["current_players"]) if data[guildStr][ts][rStr]["current_players"] is not None else str(0)}' + break + await header.edit(content='\n'.join(text)) elif ctx.custom_id.startswith('leave_'): role = ctx.guild.get_role(pitches[guildStr][timeslot]['roles'][index]) + rStr = str(role.id) 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) + await ctx.send(f'```Error: You are not in the game `{lookup[guildStr][rStr]["game_title"]}`.```', hidden=True) else: await ctx.author.remove_roles(role,reason=f'/pitch interaction by {ctx.author.display_name}') element = pitches[guildStr][timeslot]['entries'][index] - if ctx.author.id != lookup[guildStr][str(role.id)]['gm']: - data[guildStr][timeslot][str(role.id)]['current_players'] -= 1 + if ctx.author.id != lookup[guildStr][rStr]['gm']: + data[guildStr][timeslot][rStr]['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' @@ -147,10 +162,10 @@ class PitchListener(commands.Cog, name='Pitch Listener'): 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) + await ctx.send(f'You have left the game `{lookup[guildStr][rStr]["game_title"]}`.',hidden=True) + tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['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) + c = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['category'],ctx.guild.categories) if c is not None: tPos = len(ctx.guild.channels) for t in c.text_channels: @@ -159,6 +174,17 @@ class PitchListener(commands.Cog, name='Pitch Listener'): tPos = t.position if tc is not None: await tc.send(f'```{ctx.author.display_name} has left the game.```') + ts = lookup[guildStr][rStr]['time'] + p = await tc.pins() + if p is not None: + header = discord.utils.find(lambda x: x.id == data[guildStr][ts][rStr]['header_message'], p) + if header is not None: + text = header.content.split('\n') + for line, item in enumerate(text): + if 'Current Players: ' in item: + text[line] = f'Current Players: {str(data[guildStr][ts][rStr]["current_players"]) if data[guildStr][ts][rStr]["current_players"] is not None else str(0)}' + break + await header.edit(content='\n'.join(text)) yaml_dump(data, dataFile) yaml_dump(pitches, pitchesFile) diff --git a/app/cogs/membership/member_verification.py b/app/cogs/membership/member_verification.py index adf4813..3a10903 100644 --- a/app/cogs/membership/member_verification.py +++ b/app/cogs/membership/member_verification.py @@ -27,14 +27,14 @@ class MemberVerification(commands.Cog, name='Member Verification Cog'): if message.author.bot: return if message.channel.id != conf[guildStr]['channels']['signup']: return 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.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.```') await message.delete() return membership = [discord.utils.get(message.guild.roles, id=x) for x in conf[guildStr]['membership']] membership_options = [create_select_option(label=x.name, value=str(x.id), description='Membership type.') for x in membership] admin_buttons = [] if conf[guildStr]['roles'].get('student', None) is not None: admin_buttons.append(create_button(style=ButtonStyle.blurple, label='Student', emoji='📚', custom_id=f'student_{message.id}')) - admin_buttons.append(create_button(style=ButtonStyle.grey, label='Alert', emoji='⚠️', custom_id=f'alert_{message.id}')) + admin_buttons.append(create_button(style=ButtonStyle.grey, label='Review', emoji='⚠️', custom_id=f'review_{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 by `{message.author.display_name}`.```' @@ -89,36 +89,36 @@ class MemberVerification(commands.Cog, name='Member Verification Cog'): 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.```') + 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) await ctx.origin_message.delete() - elif ctx.custom_id.startswith('alert_'): - await ctx.send(f'```Membership verification alert raised.```', hidden=True) + elif ctx.custom_id.startswith('review_'): + await ctx.send(f'```Membership review requested.```', 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.```') + 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 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}`.```') + await submission.author.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}`.```') + 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 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}`.```') + await submission.author.send(f'```Your role `{selected_role.name}` has been removed in the guild `{submission.guild.name}`.```') else: pass diff --git a/app/cogs/slashcommands/secondary/player_commands.py b/app/cogs/slashcommands/secondary/player_commands.py index ec32d6d..943489d 100644 --- a/app/cogs/slashcommands/secondary/player_commands.py +++ b/app/cogs/slashcommands/secondary/player_commands.py @@ -148,7 +148,7 @@ class PlayerCommands(commands.Cog, name='Player Commands'): tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['text_channel'],ctx.guild.channels) if tc is not None: p = await tc.pins() - if p: + if p is not None: header = discord.utils.find(lambda x: x.id == hm, p) if header is not None: text = header.content.split('\n') @@ -211,7 +211,7 @@ class PlayerCommands(commands.Cog, name='Player Commands'): tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['text_channel'],ctx.guild.channels) if tc is not None: p = await tc.pins() - if p: + if p is not None: header = discord.utils.find(lambda x: x.id == hm, p) if header is not None: text = header.content.split('\n') diff --git a/app/cogs/slashcommands/secondary/tcard.py b/app/cogs/slashcommands/secondary/tcard.py index 4a2e66a..2d156af 100644 --- a/app/cogs/slashcommands/secondary/tcard.py +++ b/app/cogs/slashcommands/secondary/tcard.py @@ -37,7 +37,6 @@ class TCardCommand(commands.Cog, name='T-Card Command'): gms = yaml_load(gmFile) categories = yaml_load(categoriesFile) guildStr = str(ctx.guild.id) - # rStr = str(game.id) embed = discord.Embed( title='T-Card', description='A T-Card Has Been Played', @@ -69,12 +68,9 @@ class TCardCommand(commands.Cog, name='T-Card Command'): """Do the audio thing.""" opus = discord.opus.load_opus('/usr/lib/x86_64-linux-gnu/libopus.so.0') - # discord.opus.load_opus() - # if not discord.opus.is_loaded(): - # raise RuntimeError('Opus failed to load') for vc in ctx.channel.category.voice_channels: v = await vc.connect() - tcardaudio = discord.FFmpegPCMAudio(open("./assets/tcard.wav", "rb")) + tcardaudio = discord.PCMAudio(open("./assets/tcard.wav", "rb")) v.play(tcardaudio) while v.is_playing(): time.sleep(.1) await v.disconnect()