Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow admins to kick members from a team #16

Merged
merged 12 commits into from
Mar 10, 2024
Merged
41 changes: 41 additions & 0 deletions cogs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from discord.ext import commands
from discord import app_commands

from discord.app_commands.errors import CommandInvokeError

from typing import Literal

from src.queries.puzzle import (
Expand All @@ -13,9 +15,13 @@
create_puzzle,
delete_puzzle,
)
from src.queries.player import get_player, remove_player
from src.queries.team import get_team, get_team_members, remove_team

from src.config import config

from src.context.team import remove_member_from_team

EXEC_ID = "Executives"


Expand Down Expand Up @@ -172,6 +178,41 @@ async def set_hint_channel(self, interaction: discord.Interaction):
f"Hints will now be redirected to <#{channel.id}>"
)

@app_commands.command(
name="remove_member", description="Forcibly removes a member from a team."
)
@commands.has_role(EXEC_ID)
async def remove_member(
self, interaction: discord.Interaction, member: discord.Member
):
await interaction.response.defer(ephemeral=True)
status = await remove_member_from_team(interaction.guild, member)

if status is None:
await interaction.followup.send(
f"{member.display_name} is not part of a team.", ephemeral=True
)
return

elif status == "removed":
await interaction.followup.send(
f"{member.display_name} has been successfully kicked from the team.",
ephemeral=True,
)
return

elif status == "deleted":
try:
await interaction.followup.send(
f"{member.display_name} has been successfully kicked from the team. "
+ "Since the team is empty, the corresponding roles and channels will be deleted.",
ephemeral=True,
)
except CommandInvokeError:
return

return


async def setup(bot: commands.Bot):
await bot.add_cog(Admin(bot))
57 changes: 18 additions & 39 deletions cogs/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
from discord.ext import commands
from discord import app_commands

from discord.app_commands.errors import CommandInvokeError

import src.queries.team as team_query
import src.queries.player as player_query

from src.context.team import remove_member_from_team

BOT_ID = 1208986388226121849
MAX_TEAM_SIZE = 6
EXEC_ID = "Executives"
Expand Down Expand Up @@ -79,57 +83,32 @@ async def create_team(self, interaction: discord.Interaction, team_name: str):

@app_commands.command(name="leave", description="Leave your current team.")
async def leave_team(self, interaction: discord.Interaction):
# remove team role from user
user = interaction.user
guild = interaction.guild

await interaction.response.defer(ephemeral=True)

# get the team name from the user
discord_id = user.id
player = await player_query.get_player(discord_id)
user = interaction.user

if not player:
status = await remove_member_from_team(interaction.guild, user)

if status is None:
await interaction.followup.send(
"You are not part of a team.", ephemeral=True
)
return

team_name = player.team_name

team = await team_query.get_team(team_name)
role = guild.get_role(team.team_role_id)

await user.remove_roles(role)

# delete player
await player_query.remove_player(discord_id)

# check amount of people still in team
# if none, delete team and respective channels
# also delete the role
team_members = await team_query.get_team_members(team_name)
if team_members:
elif status == "removed":
await interaction.followup.send("You have left the team.", ephemeral=True)
return

await interaction.followup.send(
"You have left the team. Since there are no members left in the team, the channels will be deleted.",
ephemeral=True,
)

# if here, then there are no members remaining in the teams
text_channel = guild.get_channel(team.text_channel_id)
voice_channel = guild.get_channel(team.voice_channel_id)
category_channel = guild.get_channel(team.category_channel_id)

await text_channel.delete()
await voice_channel.delete()
await category_channel.delete()
await role.delete()
elif status == "deleted":
try:
await interaction.followup.send(
"You have left the team. Since there are no members left, the channels will be deleted.",
ephemeral=True,
)
except CommandInvokeError:
return

# also delete the team
await team_query.remove_team(team_name)
return

@app_commands.command(
name="invite", description="Invite another member into your team!"
Expand Down
75 changes: 75 additions & 0 deletions src/context/team.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import discord

from typing import List

from src.queries.player import get_player, remove_player
from src.queries.team import get_team, get_team_members, remove_team

from src.models.player import Player


async def get_team_channels(guild: discord.Guild, team_name: str):
team = await get_team(team_name)

voice_channel = guild.get_channel(team.voice_channel_id)
text_channel = guild.get_channel(team.text_channel_id)
category_channel = guild.get_channel(team.category_channel_id)

return [voice_channel, text_channel, category_channel]


async def delete_roles_and_channels(
roles: List[discord.Role],
channels: List[
discord.TextChannel | discord.VoiceChannel | discord.CategoryChannel
],
):
for role in roles:
await role.delete()

for channel in channels:
await channel.delete()


async def remove_role_and_player(
guild: discord.Guild, player: Player, member: discord.Member
):
if not player:
return None

team = await get_team(player.team_name)
role = guild.get_role(team.team_role_id)

await member.remove_roles(role)
await remove_player(member.id)

return role


# kicked: a True/False value that lets the function know whether the member
# is leaving the team on their own or is being kicked from the team by
# an admin
async def remove_member_from_team(guild: discord.Guild, member: discord.Member):
player = await get_player(member.id)

role = await remove_role_and_player(guild, player, member)

if not role:
return None

team_name = player.team_name

# delete team if no more members
team_members = await get_team_members(team_name)

if team_members:
return "removed"

channels = await get_team_channels(guild, team_name)

# delete roles and channels
await delete_roles_and_channels([role], channels)

await remove_team(team_name)

return "deleted"
Loading