First Commit
This commit is contained in:
Executable
+216
@@ -0,0 +1,216 @@
|
||||
import discord
|
||||
import time
|
||||
from discord.ext import commands
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from utils.sql_commands import DatabaseManager
|
||||
|
||||
# --- Localization dictionary (expand as needed) ---
|
||||
LOCALE = {
|
||||
"en": {
|
||||
"afk_set": "{user} has gone afk.{reason}",
|
||||
"afk_reason": " Reason: {reason}",
|
||||
"afk_notify": "{user} is currently unavailable.{reason}",
|
||||
"feedback_received": "Feedback received. Thank you!",
|
||||
"missing_perms": "⚠️ The bot is missing the following permissions in **{guild}**: {perms}",
|
||||
}
|
||||
}
|
||||
LANG = "en" # Set your language code here
|
||||
|
||||
|
||||
def _(key, **kwargs):
|
||||
return LOCALE[LANG][key].format(**kwargs)
|
||||
|
||||
|
||||
class Informational(commands.Cog):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.db = DatabaseManager()
|
||||
|
||||
async def cog_load(self):
|
||||
# Bot Permissions Check at startup
|
||||
for guild in self.client.guilds:
|
||||
me = guild.me
|
||||
missing = []
|
||||
if not me.guild_permissions.manage_roles:
|
||||
missing.append("Manage Roles")
|
||||
if not me.guild_permissions.manage_nicknames:
|
||||
missing.append("Manage Nicknames")
|
||||
if missing:
|
||||
owner = guild.owner
|
||||
try:
|
||||
await owner.send(
|
||||
_("missing_perms", guild=guild.name, perms=", ".join(missing))
|
||||
)
|
||||
except Exception:
|
||||
logging.warning(
|
||||
f"Could not DM owner of {guild.name} about missing permissions."
|
||||
)
|
||||
|
||||
@commands.command(name="whois")
|
||||
async def _userinfo(self, ctx, member: discord.Member = None): # type: ignore
|
||||
if member is None:
|
||||
member = ctx.message.author
|
||||
roles = [role for role in member.roles][1:]
|
||||
embed = discord.Embed(
|
||||
colour=discord.Colour.purple(),
|
||||
timestamp=ctx.message.created_at,
|
||||
title=f"User Info - {member}",
|
||||
)
|
||||
embed.set_thumbnail(url=member.display_avatar)
|
||||
embed.set_footer(text=f"Requested by {ctx.author}")
|
||||
|
||||
embed.add_field(name="ID:", value=member.id)
|
||||
embed.add_field(name="Display Name:", value=member.display_name)
|
||||
embed.add_field(
|
||||
name="Created Account On:",
|
||||
value=member.created_at.strftime("%a, %#d %B %Y, %I:%M %p UTC"),
|
||||
)
|
||||
embed.add_field(
|
||||
name="Joined Server On:",
|
||||
value=member.joined_at.strftime("%a, %#d %B %Y, %I:%M %p UTC"), # type: ignore
|
||||
)
|
||||
embed.add_field(name="Roles:", value="".join([role.mention for role in roles]))
|
||||
embed.add_field(name="Highest Role:", value=member.top_role.mention)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="serverInfo")
|
||||
@commands.has_permissions(view_audit_log=True) # Example permission
|
||||
async def _server(self, ctx):
|
||||
embed = discord.Embed(
|
||||
title=f"{ctx.guild.name} Info",
|
||||
description="Information of this Server",
|
||||
color=discord.Colour.blue(),
|
||||
)
|
||||
embed.add_field(name="🆔Server ID", value=f"{ctx.guild.id}", inline=True)
|
||||
embed.add_field(
|
||||
name="📆Created On",
|
||||
value=ctx.guild.created_at.strftime("%b %d %Y"),
|
||||
inline=True,
|
||||
)
|
||||
embed.add_field(name="👑Owner", value=f"{ctx.guild.owner.mention}", inline=True)
|
||||
embed.add_field(
|
||||
name="👥Members", value=f"{ctx.guild.member_count} Members", inline=True
|
||||
)
|
||||
embed.add_field(
|
||||
name="💬Channels",
|
||||
value=f"{len(ctx.guild.text_channels)} Text | {len(ctx.guild.voice_channels)} Voice",
|
||||
inline=True,
|
||||
)
|
||||
embed.set_thumbnail(url=ctx.guild.icon)
|
||||
embed.set_footer(text="⭐ • Duo")
|
||||
embed.set_author(name=f"{ctx.author.name}", icon_url=ctx.message.author.avatar)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="afk")
|
||||
@commands.cooldown(1, 10, commands.BucketType.user)
|
||||
async def _afk(self, ctx, *reason):
|
||||
afk_reason = " ".join(reason)
|
||||
timestamp = datetime.utcnow().isoformat()
|
||||
# Store AFK reason and timestamp in DB
|
||||
self.db.execute_query(
|
||||
"REPLACE INTO afk_status (USERID, GUILDID, REASON, TIMESTAMP) VALUES (%s, %s, %s, %s)",
|
||||
(ctx.author.id, ctx.guild.id, afk_reason, timestamp),
|
||||
)
|
||||
msg = _(
|
||||
"afk_set",
|
||||
user=ctx.author.mention,
|
||||
reason=_("afk_reason", reason=afk_reason) if afk_reason else "",
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
# Prevent stacking [AFK]
|
||||
try:
|
||||
current_nick = ctx.author.nick or ctx.author.name
|
||||
if "[AFK]" not in current_nick:
|
||||
await ctx.author.edit(nick=f"{current_nick} [AFK]")
|
||||
except discord.Forbidden:
|
||||
logging.warning(f"Missing permissions to edit nickname for {ctx.author}")
|
||||
except Exception as e:
|
||||
logging.error(f"Error editing nickname: {e}")
|
||||
|
||||
guild = ctx.guild
|
||||
try:
|
||||
role = discord.utils.get(ctx.guild.roles, name="AFK")
|
||||
if not role:
|
||||
role = await guild.create_role(name="AFK", hoist=True)
|
||||
all_roles = await guild.fetch_roles()
|
||||
num_roles = len(all_roles)
|
||||
await role.edit(reason=None, position=num_roles - 2)
|
||||
await ctx.author.add_roles(role)
|
||||
except discord.Forbidden:
|
||||
logging.warning("Missing permissions to create/add AFK role.")
|
||||
except Exception as e:
|
||||
logging.error(f"Error handling AFK role: {e}")
|
||||
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
|
||||
@commands.command(name="afklist")
|
||||
async def afk_list(self, ctx):
|
||||
afks = self.db.fetch_all(
|
||||
"SELECT USERID, REASON, TIMESTAMP FROM afk_status WHERE GUILDID = %s",
|
||||
(ctx.guild.id,),
|
||||
)
|
||||
if not afks:
|
||||
await ctx.reply("No one is AFK right now.")
|
||||
return
|
||||
lines = []
|
||||
for afk in afks:
|
||||
member = ctx.guild.get_member(int(afk["USERID"]))
|
||||
reason = afk["REASON"] or "No reason given."
|
||||
timestamp = afk.get("TIMESTAMP")
|
||||
# Convert timestamp string to datetime
|
||||
if isinstance(timestamp, str):
|
||||
try:
|
||||
timestamp = datetime.fromisoformat(timestamp)
|
||||
except Exception:
|
||||
timestamp = None
|
||||
if timestamp:
|
||||
duration = datetime.utcnow() - timestamp
|
||||
duration_str = str(duration).split(".")[0]
|
||||
else:
|
||||
duration_str = "unknown duration"
|
||||
lines.append(
|
||||
f"{member.mention if member else afk['USERID']} - {reason} (AFK for {duration_str})"
|
||||
)
|
||||
await ctx.send("\n".join(lines))
|
||||
|
||||
@commands.command(name="feedback")
|
||||
@commands.cooldown(1, 30, commands.BucketType.user)
|
||||
async def _feedback(self, ctx, *info):
|
||||
feedback_text = " ".join(info)
|
||||
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
||||
user = f"{ctx.author} ({ctx.author.id})"
|
||||
# Store feedback in DB
|
||||
self.db.execute_query(
|
||||
"INSERT INTO feedback (USER, GUILDID, TIMESTAMP, CONTENT) VALUES (%s, %s, %s, %s)",
|
||||
(user, ctx.guild.id if ctx.guild else None, timestamp, feedback_text),
|
||||
)
|
||||
await ctx.reply(_("feedback_received"))
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command_error(self, ctx, error):
|
||||
# Notify admin if permissions are missing
|
||||
if isinstance(
|
||||
error, (commands.MissingPermissions, commands.BotMissingPermissions)
|
||||
):
|
||||
perms = getattr(error, "missing_perms", None)
|
||||
perms_str = ", ".join(perms) if perms else "Unknown"
|
||||
owner = ctx.guild.owner if ctx.guild else None
|
||||
if owner:
|
||||
try:
|
||||
await owner.send(
|
||||
_("missing_perms", guild=ctx.guild.name, perms=perms_str)
|
||||
)
|
||||
except Exception:
|
||||
logging.warning(
|
||||
f"Could not DM owner of {ctx.guild.name} about missing permissions."
|
||||
)
|
||||
raise error # Let default handler run too
|
||||
|
||||
|
||||
async def setup(client):
|
||||
await client.add_cog(Informational(client))
|
||||
Reference in New Issue
Block a user