added roletrack

This commit is contained in:
Lilac-Rose
2025-12-30 00:07:39 +01:00
parent b62b9adf8f
commit c2dbb3d5e9
2 changed files with 265 additions and 0 deletions

125
commands/roletrack.py Normal file
View File

@@ -0,0 +1,125 @@
import discord
from discord import app_commands
from discord.ext import commands
import aiosqlite
import os
class RoleTrack(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.db_path = os.path.join(os.path.dirname(__file__), 'roletrack.db')
bot.loop.create_task(self.init_db())
async def init_db(self):
"""Initialize the database tables if they don't exist"""
async with aiosqlite.connect(self.db_path) as db:
# Table for tracking opt-in status
await db.execute('''
CREATE TABLE IF NOT EXISTS role_tracking_users (
user_id INTEGER,
guild_id INTEGER,
opted_in INTEGER DEFAULT 1,
PRIMARY KEY (user_id, guild_id)
)
''')
# Table for storing role data
await db.execute('''
CREATE TABLE IF NOT EXISTS tracked_roles (
user_id INTEGER,
guild_id INTEGER,
role_id INTEGER,
role_name TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, guild_id, role_id)
)
''')
await db.commit()
async def is_opted_in(self, user_id: int, guild_id: int) -> bool:
"""Check if a user is opted into role tracking"""
async with aiosqlite.connect(self.db_path) as db:
async with db.execute('''
SELECT opted_in FROM role_tracking_users
WHERE user_id = ? AND guild_id = ?
''', (user_id, guild_id)) as cursor:
result = await cursor.fetchone()
return result[0] == 1 if result else False
async def save_user_roles(self, member: discord.Member):
"""Save all roles for a user (excluding @everyone)"""
if not await self.is_opted_in(member.id, member.guild.id):
return
async with aiosqlite.connect(self.db_path) as db:
# Clear existing roles for this user in this guild
await db.execute('''
DELETE FROM tracked_roles
WHERE user_id = ? AND guild_id = ?
''', (member.id, member.guild.id))
# Save current roles (excluding @everyone)
for role in member.roles:
if role.id != member.guild.id: # Skip @everyone role
await db.execute('''
INSERT INTO tracked_roles (user_id, guild_id, role_id, role_name)
VALUES (?, ?, ?, ?)
''', (member.id, member.guild.id, role.id, role.name))
await db.commit()
@app_commands.command(name="roletrack", description="Manage role tracking opt-in status")
@app_commands.describe(
setting="Choose to opt in or opt out of role tracking"
)
@app_commands.choices(setting=[
app_commands.Choice(name="opt_in", value="opt_in"),
app_commands.Choice(name="opt_out", value="opt_out")
])
async def roletrack(self, interaction: discord.Interaction, setting: app_commands.Choice[str]):
"""Command to opt in or opt out of role tracking"""
async with aiosqlite.connect(self.db_path) as db:
if setting.value == "opt_in":
# Opt the user in
await db.execute('''
INSERT OR REPLACE INTO role_tracking_users (user_id, guild_id, opted_in)
VALUES (?, ?, 1)
''', (interaction.user.id, interaction.guild.id))
await db.commit()
# Save current roles (outside the db context)
await self.save_user_roles(interaction.user)
embed = discord.Embed(
title="✅ Role Tracking Enabled",
description="You've been opted into role tracking. If you leave and rejoin this server, your roles will be automatically restored.",
color=discord.Color.green()
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif setting.value == "opt_out":
# Opt the user out
await db.execute('''
INSERT OR REPLACE INTO role_tracking_users (user_id, guild_id, opted_in)
VALUES (?, ?, 0)
''', (interaction.user.id, interaction.guild.id))
# Delete their tracked roles
await db.execute('''
DELETE FROM tracked_roles
WHERE user_id = ? AND guild_id = ?
''', (interaction.user.id, interaction.guild.id))
await db.commit()
embed = discord.Embed(
title="❌ Role Tracking Disabled",
description="You've been opted out of role tracking. Your saved roles have been deleted.",
color=discord.Color.red()
)
await interaction.response.send_message(embed=embed, ephemeral=True)
async def setup(bot):
await bot.add_cog(RoleTrack(bot))

140
events/roletrack.py Normal file
View File

@@ -0,0 +1,140 @@
import discord
from discord.ext import commands
import sqlite3
import os
import asyncio
class RoleTrackEvents(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.db_path = os.path.join(os.path.dirname(__file__), '..', 'roletrack.db')
def is_opted_in(self, user_id: int, guild_id: int) -> bool:
"""Check if a user is opted into role tracking"""
conn = sqlite3.connect(self.db_path)
c = conn.cursor()
c.execute('''
SELECT opted_in FROM role_tracking_users
WHERE user_id = ? AND guild_id = ?
''', (user_id, guild_id))
result = c.fetchone()
conn.close()
return result[0] == 1 if result else False
def get_tracked_roles(self, user_id: int, guild_id: int):
"""Retrieve tracked roles for a user"""
conn = sqlite3.connect(self.db_path)
c = conn.cursor()
c.execute('''
SELECT role_id, role_name FROM tracked_roles
WHERE user_id = ? AND guild_id = ?
''', (user_id, guild_id))
roles = c.fetchall()
conn.close()
return roles
def save_user_roles(self, member: discord.Member):
"""Save all roles for a user (excluding @everyone)"""
if not self.is_opted_in(member.id, member.guild.id):
return
conn = sqlite3.connect(self.db_path)
c = conn.cursor()
# Clear existing roles for this user in this guild
c.execute('''
DELETE FROM tracked_roles
WHERE user_id = ? AND guild_id = ?
''', (member.id, member.guild.id))
# Save current roles (excluding @everyone)
for role in member.roles:
if role.id != member.guild.id: # Skip @everyone role
c.execute('''
INSERT INTO tracked_roles (user_id, guild_id, role_id, role_name)
VALUES (?, ?, ?, ?)
''', (member.id, member.guild.id, role.id, role.name))
conn.commit()
conn.close()
@commands.Cog.listener()
async def on_member_join(self, member: discord.Member):
"""Restore roles when a tracked user rejoins"""
if member.bot:
return
# Check if user is opted in
if not self.is_opted_in(member.id, member.guild.id):
return
# Get their tracked roles
tracked_roles = self.get_tracked_roles(member.id, member.guild.id)
if not tracked_roles:
return
# Wait a moment for Discord to fully process the join
await asyncio.sleep(1)
# Restore roles
roles_to_add = []
missing_roles = []
for role_id, role_name in tracked_roles:
role = member.guild.get_role(role_id)
if role:
# Check if bot can assign this role (bot's highest role must be higher)
if role < member.guild.me.top_role and not role.is_default():
roles_to_add.append(role)
else:
missing_roles.append(role_name)
# Add roles
if roles_to_add:
try:
await member.add_roles(*roles_to_add, reason="Role tracking: User rejoined server")
print(f"Restored {len(roles_to_add)} roles for {member.name} ({member.id})")
except discord.Forbidden:
print(f"Failed to restore roles for {member.name}: Missing permissions")
except discord.HTTPException as e:
print(f"Failed to restore roles for {member.name}: {e}")
# Log if there were missing roles
if missing_roles:
print(f"Could not restore the following roles for {member.name} (roles no longer exist): {', '.join(missing_roles)}")
@commands.Cog.listener()
async def on_member_update(self, before: discord.Member, after: discord.Member):
"""Update tracked roles when a user's roles change"""
if after.bot:
return
# Check if user is opted in
if not self.is_opted_in(after.id, after.guild.id):
return
# Check if roles actually changed
if before.roles == after.roles:
return
# Save updated roles
self.save_user_roles(after)
print(f"Updated tracked roles for {after.name} ({after.id})")
@commands.Cog.listener()
async def on_member_remove(self, member: discord.Member):
"""Optional: Log when a tracked user leaves"""
if member.bot:
return
if self.is_opted_in(member.id, member.guild.id):
print(f"Tracked user {member.name} ({member.id}) left the server. Roles are saved for restoration.")
async def setup(bot):
await bot.add_cog(RoleTrackEvents(bot))