217 lines
8.5 KiB
Python
Executable File
217 lines
8.5 KiB
Python
Executable File
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))
|