Skip to content

Commit

Permalink
added persistent role,levelling features
Browse files Browse the repository at this point in the history
  • Loading branch information
sarzz2 committed Oct 11, 2023
1 parent 3166b77 commit b0163ff
Show file tree
Hide file tree
Showing 11 changed files with 449 additions and 4 deletions.
238 changes: 238 additions & 0 deletions bot/cogs/levelling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import datetime
import random

import discord
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import has_permissions

from bot import core
from bot.models import IgnoredChannel, Levels

REQUIRED_XP = [
0,
100,
255,
475,
770,
1150,
1625,
2205,
2900,
3720,
4675,
5775,
7030,
8450,
10045,
11825,
13800,
15980,
18375,
20995,
23850,
26950,
30305,
33925,
37820,
42000,
46475,
51255,
56350,
61770,
67525,
73625,
80080,
86900,
94095,
101675,
109650,
118030,
126825,
136045,
145700,
155800,
166355,
177375,
188870,
200850,
213325,
226305,
239800,
253820,
268375,
283475,
299130,
315350,
332145,
349525,
367500,
386080,
405275,
425095,
445550,
466650,
488405,
510825,
533920,
557700,
582175,
607355,
633250,
659870,
687225,
715325,
744180,
773800,
804195,
835375,
867350,
900130,
933725,
968145,
1003400,
1039500,
1076455,
1114275,
1152970,
1192550,
1233025,
1274405,
1316700,
1359920,
1404075,
1449175,
1495230,
1542250,
1590245,
1639225,
1689200,
1740180,
1899250,
1792175,
1845195,
]
IGNORED_CHANNEL = {}


class Levelling(commands.Cog):
def __init__(self, bot):
self.bot = bot

@commands.Cog.listener()
async def on_ready(self):
for guild in self.bot.guilds:
channel_id = await IgnoredChannel.get(guild_id=guild.id)
if guild.id not in IGNORED_CHANNEL:
IGNORED_CHANNEL[guild.id] = [channel_id]
else:
IGNORED_CHANNEL[guild.id].append(channel_id)
print(IGNORED_CHANNEL)

@commands.Cog.listener()
async def on_message(self, message):
if message.author.bot:
return

# Check if message is sent in ignored channel
ignored_channel = await IgnoredChannel.get(message.guild.id)
for i in range(len(ignored_channel)):
if message.channel.id == ignored_channel[i].channel_id:
return

# Generate random XP to be added
xp = random.randint(5, 25)
# Add the XP and update the DB
data = await Levels.update(guild_id=message.guild.id, user_id=message.author.id, total_xp=xp)
await self._check_level_up(data, message.author)

@app_commands.command()
async def rank(self, interaction: core.InteractionType, member: discord.Member = None):
"""Check the rank of another member or yourself
example:
- /rank @Noobmaster
- /rank"""
if member is None:
member = interaction.user

query = """WITH ordered_users AS (
SELECT
user_id,guild_id,total_xp,
ROW_NUMBER() OVER (ORDER BY levels.total_xp DESC) AS rank
FROM levels
WHERE guild_id = $2)
SELECT rank,total_xp,user_id,guild_id
FROM ordered_users WHERE ordered_users.user_id = $1;"""
data = await Levels.fetchrow(query, member.id, member.guild.id)
if data is None:
return await interaction.response.send_message(f"{member} is not ranked yet!")
for level, j in enumerate(REQUIRED_XP):
if data.total_xp <= j:
embed = discord.Embed(
title=f"Rank: {data.rank}\nLevel: {level - 1}\nTotal XP:{data.total_xp}",
timestamp=datetime.datetime.utcnow(),
colour=discord.Colour.blurple(),
)
embed.set_thumbnail(url=member.avatar)
return await interaction.response.send_message(embed=embed)

@app_commands.command()
@app_commands.checks.has_permissions(administrator=True)
async def ignore_channel(self, interaction: core.InteractionType, channel: discord.TextChannel):
"""Add the channel to the ignored channel list to not gain XP
Example:
/ignore_channel #channel"""
await IgnoredChannel.insert(channel.guild.id, channel.id)
await interaction.response.send_message(f"{channel} has been ignored from gaining XP.")

@app_commands.command()
@app_commands.checks.has_permissions(administrator=True)
@has_permissions(administrator=True)
async def unignore_channel(self, interaction: core.InteractionType, channel: discord.TextChannel):
"""Remove channel from ignored channel list
Example:
/unignore_channel #channel"""
await IgnoredChannel.delete(channel.guild.id, channel.id)
await interaction.response.send_message(f"{channel} has been removed from ignored channel list")

@app_commands.command()
@app_commands.checks.has_permissions(administrator=True)
async def give_xp(self, interaction: core.InteractionType, xp: int, member: discord.Member):
"""Give XP to specific user
Example:
/give_xp 1000 user"""
data = await Levels.update(member.guild.id, member.id, xp)
await self._check_level_up(data, member)
await interaction.response.send_message(f"{xp} XP has been added to user {member}")

@app_commands.command()
@app_commands.checks.has_permissions(administrator=True)
async def remove_xp(self, interaction: core.InteractionType, xp: int, member: discord.Member):
"""Remove XP from user
Example:
/remove_xp 100 user"""
data = await Levels.remove_xp(member.guild.id, member.id, xp)
await self._check_level_up(data, member)
await interaction.response.send_message(f"{xp} XP has been removed from user {member}")

async def _check_level_up(self, data, member: discord.Member):
"""Function to check if user's level has changed and trigger the event to assign the roles"""
# Calculating old and new level
try:
for level, j in enumerate(REQUIRED_XP):
if data.old_total_xp <= j:
old_level = level - 1
break
for level, j in enumerate(REQUIRED_XP):
if data.total_xp <= j:
new_level = level - 1
break
# If the level has changed call level_up to handle roles change
if old_level != new_level:
self.bot.dispatch("level_up", new_level=new_level, member=member)
except AttributeError:
pass


async def setup(bot: commands.Bot):
await bot.add_cog(Levelling(bot=bot))
24 changes: 24 additions & 0 deletions bot/cogs/persistent_roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from discord.ext import commands

from bot.models import PersistentRole


class PersistentRoles(commands.Cog):
def __init__(self, bot):
self.bot = bot

@commands.Cog.listener()
async def on_member_join(self, member):
# Get the data
data = await PersistentRole.get(member.guild.id, member.id)
# Return if data for specified user and guild does not exist
if data is None:
return
# Add the roles to the user if data exists
else:
for i in range(len(data)):
await member.add_roles(member.guild.get_role(data[i].role_id))


async def setup(bot: commands.Bot):
await bot.add_cog(PersistentRoles(bot=bot))
15 changes: 15 additions & 0 deletions bot/extensions/challenges/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from bot import core
from bot.config import settings
from bot.models import LevellingRole, PersistentRole

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,3 +49,17 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
await self.bot.http.add_role(
guild_id=self.bot.guild.id, user_id=payload.user_id, role_id=self.participant_role.id
)

@commands.Cog.listener()
async def on_level_up(self, new_level, member: discord.Member):
"""Add roles when user levels up"""
data = await LevellingRole.get(guild_id=member.guild.id)
for i in range(len(data)):
# Adding roles when user levels up
if new_level >= data[i].level and member.guild.get_role(data[i].role_id) not in member.roles:
await member.add_roles(member.guild.get_role(data[i].role_id))
await PersistentRole.insert(guild_id=member.guild.id, user_id=member.id, role_id=data[i].role_id)
# Removing roles when users level down using remove_xp command
elif new_level <= data[i].level and member.guild.get_role(data[i].role_id) in member.roles:
await member.remove_roles(member.guild.get_role(data[i].role_id))
await PersistentRole.remove(guild_id=member.guild.id, user_id=member.id)
12 changes: 10 additions & 2 deletions bot/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
from .gconfig import FilterConfig
from .ignored_channel import IgnoredChannel
from .levelling_role import LevellingRole
from .levels import Levels
from .message import Message
from .model import Model
from .persistent_role import PersistentRole
from .rep import Rep
from .tag import Tag
from .user import User

__all__ = ( # Fixes F401
__all__ = (
Model,
FilterConfig,
Message,
Rep,
Tag,
User,
)
Levels,
PersistentRole,
IgnoredChannel,
LevellingRole,
) # Fixes F401
23 changes: 23 additions & 0 deletions bot/models/ignored_channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from .model import Model


class IgnoredChannel(Model):
guild_id: int
channel_id: int

@classmethod
async def get(cls, guild_id: int):
query = """ SELECT * FROM ignored_channels WHERE guild_id = $1"""
return await cls.fetch(query, guild_id)

@classmethod
async def insert(cls, guild_id: int, channel_id: int):
query = """INSERT INTO ignored_channels (guild_id,channel_id) VALUES($1, $2)
ON CONFLICT (guild_id,channel_id) DO NOTHING
RETURNING guild_id, channel_id"""
return await cls.fetch(query, guild_id, channel_id)

@classmethod
async def delete(cls, guild_id: int, channel_id: int):
query = """DELETE FROM ignored_channel WHERE guild_id= $1 and channel_id = $2"""
return await cls.fetch(query, guild_id, channel_id)
12 changes: 12 additions & 0 deletions bot/models/levelling_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .model import Model


class LevellingRole(Model):
guild_id: int
role_id: int
level: int

@classmethod
async def get(cls, guild_id: int):
query = """SELECT guild_id, role_id, level FROM levelling_roles WHERE guild_id=$1"""
return await cls.fetch(query, guild_id)
Loading

0 comments on commit b0163ff

Please sign in to comment.