Skip to content
6 changes: 3 additions & 3 deletions bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ async def send_restart_message(self: commands.Bot):
embed = simple_embed(message=f"Build version: [{commit_hash}]({github_repo_link}/commit/{commit_hash})",
title="")
embed.set_footer(text=commit_message)
await self.sys_log_channel.send(
embed=embed,
)
# await self.sys_log_channel.send(
# embed=embed,
# )
except discord.Forbidden:
pass

Expand Down
6 changes: 3 additions & 3 deletions bot/cogs/afk.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
from bot.bot import Bot

class AFK(commands.Cog):
def __init__(self, bot: Bot) -> None:
def __init__(self, bot: "Bot") -> None:
self.bot = bot
self.manager = bot.afk_manager
self.cleanup_expired.start()

def cog_unload(self):
self.cleanup_expired.cancel()

@app_commands.command(name="setafk", description="Set AFK status.")
async def setafk(
@app_commands.command(name="set_afk", description="Set AFK status.")
async def set_afk(
self,
interaction: discord.Interaction,
hours: Optional[int] = None,
Expand Down
5 changes: 5 additions & 0 deletions bot/cogs/anti_raid.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ async def handle_bot_trap_raid(self, member: discord.Member):
reason=self.BOT_TRAP_BAN_REASON,
delete_message_days=1,
)
await self.bot.progression_manager.set_ban_status(
user_id=member.id,
guild_id=guild.id,
status=True
)
except discord.Forbidden:
return

Expand Down
170 changes: 143 additions & 27 deletions bot/cogs/button_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,132 @@

from bot.constants import (
challenger_role_id, accepting_team_invites_role_id, tortoise_guild_id,
join_a_team_channel_id, teams_dashboard_message_id
join_a_team_channel_id, teams_dashboard_message_id, server_link, bot_avatar_url
)
from bot.utils.checks import tortoise_bot_developer_only
from bot.utils.embed_handler import info, failure
from bot.utils.embed_handler import info, failure, success


class TicketReasonSelect(discord.ui.Select):
"""Dropdown menu for selecting the ticket/ban appeal reason."""

def __init__(self, cog: "TortoiseDM"):
options = [
discord.SelectOption(
label="Accidentally Selected 'I am Bot' Option",
value="accidental_trap_victim",
description="I accidentally selected 'I am Bot' option while joining.",
emoji="🤖"
),
discord.SelectOption(label="Unfair Ban", value="unfair_ban", description="I feel my ban was unjust.",
emoji="⚖️"),
discord.SelectOption(label="Apology / Second Chance", value="apology",
description="I admit my mistake and want to apologize.", emoji="🙏"),
discord.SelectOption(label="Compromised Account", value="compromised",
description="My account was hacked when the violation occurred.", emoji="🛡️"),
discord.SelectOption(label="Other Reason", value="other", description="Any other reason not listed above.",
emoji="📝"),
]
super().__init__(
placeholder="Choose the reason for your appeal...",
min_values=1,
max_values=1,
options=options
)
self.cog = cog

async def callback(self, interaction: discord.Interaction):
user = interaction.user
reason = self.values[0]

reason_mappings = {
"accidental_trap_victim": "Accidentally Selected 'I am Bot' Option",
"unfair_ban": "Unfair Ban Appeal",
"apology": "Apology / Second Chance Request",
"compromised": "Compromised Account Appeal",
"other": "Other / Unspecified Reason"
}
chosen_reason = reason_mappings.get(reason, "Unspecified Reason")

self.disabled = True

if reason == "accidental_trap_victim":
await interaction.response.edit_message(view=self.view)

is_banned = await self.cog.bot.progression_manager.is_auto_banned(user_id=user.id,
guild_id=tortoise_guild_id)

if is_banned:
guild = self.cog.bot.get_guild(tortoise_guild_id)

try:
ban_entry = await guild.fetch_ban(discord.Object(id=user.id))
target_user = ban_entry.user

await guild.unban(target_user, reason="Auto unbanned via Honeypot Trap Appeal panel.")
await self.cog.bot.safe_send(
target_user,
content=server_link,
embed=info(
"You have been unbanned in Tortoise Community\n"
"Please use the invite link to rejoin the server\n",
self.cog.bot.user,
"Ban Lifted!",
"Welcome back to Tortoise Programming Community!",
)
)

await self.cog.bot.progression_manager.set_ban_status(user_id=user.id,
guild_id=tortoise_guild_id,
status=False)

await interaction.followup.send(f"✅ Successfully unbanned. You may rejoin!", ephemeral=True)

except discord.NotFound:
await interaction.followup.send("You are not currently recorded on the server ban list.",
ephemeral=True)
except discord.HTTPException:
await interaction.followup.send(
"❌ Something went wrong while attempting to unban. Try again later.", ephemeral=True)
else:
await interaction.followup.send(
embed=failure(
"Our records indicate you weren't banned by the automated bot trap.\nPlease select a different appeal reason."),
ephemeral=True
)

else:
await interaction.response.edit_message(
content="⏳ Processing your request and opening a ticket...",
view=self.view
)

try:
embed = info(
f"Your ban appeal request is logged.\n"
f"**Reason:** {chosen_reason}\n"
"Please wait for a moderator to respond.\n\n",
self.cog.bot.user,
"Ticket Created!"
)
embed.set_footer(text="NOTE: Please remain in this server until this ticket is closed.")
await user.send(embed=embed)
except discord.HTTPException:
await interaction.followup.send(
"❌ I couldn't send you a Direct Message. Please enable DMs from server members and try again.",
ephemeral=True
)
return

await self.cog.create_mod_mail(user, reason=chosen_reason, source="panel", ping=False)


class TicketReasonView(discord.ui.View):
"""Temporary ephemeral view containing the reason dropdown."""

def __init__(self, cog: "TortoiseDM"):
super().__init__(timeout=60)
self.add_item(TicketReasonSelect(cog))


class ModMailStartView(discord.ui.View):
Expand Down Expand Up @@ -45,30 +167,11 @@ async def start_modmail(self, interaction: discord.Interaction, button: discord.
cog.cool_down.add_to_cool_down(user.id)

await interaction.response.send_message(
"📩 Opening mod mail in your DMs...",
ephemeral=True,
delete_after=5,
"📩 Please select the reason for your ban appeal below:",
view=TicketReasonView(cog),
ephemeral=True
)

try:
embed = info(
"Your ban appeal request is logged.\n"
"Please wait for a moderator to respond.\n\n",
user,
"Ticket Created!"
)
embed.set_footer(text="NOTE: Please remain in this server until this ticket is closed.")
await user.send(embed=embed)
except discord.HTTPException:
await interaction.followup.send(
"I couldn't DM you. Please enable DMs.",
ephemeral=True
)
return

await cog.create_mod_mail(user, source="panel")


class NotifyButton(discord.ui.View):
"""Persistent button view for challenge notifications."""

Expand Down Expand Up @@ -207,20 +310,33 @@ async def post_challenge_notification(
description="Post the mod mail contact panel."
)
@app_commands.check(tortoise_bot_developer_only)
async def post_panel(self, interaction: discord.Interaction):
async def post_panel(self, interaction: discord.Interaction, channel_id: str):
await interaction.response.defer(ephemeral=True)
try:
target_id = int(channel_id)
except ValueError:
await interaction.followup.send("❌ Please provide a valid numerical Channel ID.", ephemeral=True)
return

channel = interaction.guild.get_channel(target_id)

await channel.purge(limit=1)

embed = discord.Embed(
title="Ban appeal",
description="Use the button below to create a ticket and submit a ban appeal.",
color=discord.Color.dark_green()
)

embed.set_footer(text="Tortoise Programming Community", icon_url=self.bot.user.avatar.url)
embed.set_footer(text="Tortoise Programming Community", icon_url=bot_avatar_url)

await interaction.response.send_message(
await channel.send(
embed=embed,
view=ModMailStartView()
)
await interaction.followup.send(
embed=success("Done")
)

@app_commands.command(
name="post_team_invites_notification",
Expand Down
30 changes: 15 additions & 15 deletions bot/cogs/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

STATIC_PROJECTS_DATA = [
{
"name": "Tortoise-Bot",
"name": "tortoise-bot",
"html_url": "https://github.com/Tortoise-Community/Tortoise-Bot",
"web_link": "https://github.com/Tortoise-Community/Tortoise-Bot",
"forks_count": 21,
Expand All @@ -24,7 +24,7 @@
"short_desc": "Fully functional Bot for Discord coded in Discord.py",
},
{
"name": "Runtime-Bot",
"name": "runtime-bot",
"html_url": "https://github.com/Tortoise-Community/Runtime-Bot",
"web_link": "https://github.com/Tortoise-Community/Runtime-Bot",
"forks_count": 1,
Expand All @@ -35,7 +35,7 @@
"short_desc": "Discord bot for executing code directly in chat using the Hermes sandbox engine.",
},
{
"name": "Snappy-Bot",
"name": "snappy-bot",
"html_url": "https://github.com/Tortoise-Community/Snappy-Bot",
"web_link": "https://github.com/Tortoise-Community/Snappy-Bot",
"forks_count": 1,
Expand All @@ -46,20 +46,20 @@
"short_desc": "Snappy is a lightweight Discord bot built using discord.py v2+",
},
{
"name": "Backend",
"html_url": "https://github.com/Tortoise-Community/Backend",
"web_link": "https://github.com/Tortoise-Community/Backend",
"name": "site-backend",
"html_url": "https://github.com/Tortoise-Community/Site-Backend",
"web_link": "https://github.com/Tortoise-Community/Site-Backend",
"forks_count": 1,
"commit_count": 573,
"stargazers_count": 8,
"contributors_count": 0,
"language": "Python",
"language": "Django",
"short_desc": "Website build with django for the Tortoise Community discord server",
},
{
"name": "Frontend",
"html_url": "https://github.com/Tortoise-Community/Frontend",
"web_link": "https://github.com/Tortoise-Community/Frontend",
"name": "site-frontend",
"html_url": "https://github.com/Tortoise-Community/Site-Frontend",
"web_link": "https://github.com/Tortoise-Community/Site-Frontend",
"forks_count": 1,
"commit_count": 119,
"stargazers_count": 1,
Expand All @@ -68,15 +68,15 @@
"short_desc": "Web frontend built with React for Tortoise Community discord server",
},
{
"name": "BladeList",
"html_url": "https://github.com/Bladelist/Bladelist",
"web_link": "https://github.com/Bladelist/Bladelist",
"name": "code-studio",
"html_url": "https://github.com/Tortoise-Community/Code-Studio",
"web_link": "https://github.com/Tortoise-Community/Code-Studio",
"forks_count": 7,
"commit_count": 290,
"stargazers_count": 9,
"contributors_count": 0,
"language": "Django",
"short_desc": "An open-source Discord Bot and Server Listing site built with Django.",
"language": "React",
"short_desc": "An open-source platform for practising DSA with community-driven resources",
},
]

Expand Down
4 changes: 2 additions & 2 deletions bot/cogs/moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,10 +334,10 @@ async def unban(self, interaction: discord.Interaction, user_id: str, reason: st
await interaction.guild.unban(user=user, reason=reason)
try:
await user.send(
content=constants.server_link,
embed=info(
"You have been unbanned in Tortoise Community\n"
"Please use the below link to rejoin the server\n"
f"👉 [Invite Link]({constants.server_link}) ",
"Please use the invite link to rejoin the server\n",
self.bot.user,
"Ban Lifted!",
"Welcome back to Tortoise Programming Community!",
Expand Down
Loading
Loading