diff --git a/README.md b/README.md index 5ffd023..0bb7fc2 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Cog Function | sayurl | **Alpha** |
Convert any URL into text and post to discordNo error checking and pretty spammy
| | secrethitler | **Incomplete** |
Play the Secret Hitler gameConcept, no work done yet
| | stealemoji | **Alpha** |
Steals any custom emoji it sees in a reactionSome planned upgrades for server generation
| +| timerole | **Alpha** |
Add roles to members after specified time on the serverUpgraded from V2, please report any bugs
| | werewolf | **Alpha** |
Play the classic party game Werewolf within discordAnother massive project currently being developed, will be fully customizable
| diff --git a/timerole/__init__.py b/timerole/__init__.py new file mode 100644 index 0000000..9e7f94b --- /dev/null +++ b/timerole/__init__.py @@ -0,0 +1,5 @@ +from .timerole import Timerole + + +def setup(bot): + bot.add_cog(Timerole(bot)) diff --git a/timerole/info.json b/timerole/info.json new file mode 100644 index 0000000..3ea5a0e --- /dev/null +++ b/timerole/info.json @@ -0,0 +1,22 @@ +{ + "author": [ + "Bobloy" + ], + "bot_version": [ + 3, + 0, + 0 + ], + "description": "Apply roles based on the # of days on server", + "hidden": false, + "install_msg": "Thank you for installing timerole. Configure with [p]timerole", + "requirements": [], + "short": "Apply roles after # of days", + "tags": [ + "bobloy", + "utilities", + "tools", + "tool", + "roles" + ] +} \ No newline at end of file diff --git a/timerole/timerole.py b/timerole/timerole.py new file mode 100644 index 0000000..fb2fff2 --- /dev/null +++ b/timerole/timerole.py @@ -0,0 +1,143 @@ +import asyncio +from datetime import timedelta, datetime + +import discord +from redbot.core import Config, checks, commands +from redbot.core.bot import Red +from redbot.core.utils.chat_formatting import pagify + + +class Timerole: + """Add roles to users based on time on server""" + + def __init__(self, bot: Red): + self.bot = bot + self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) + default_global = {} + default_guild = { + 'announce': None, + 'roles': {} + } + + self.config.register_global(**default_global) + self.config.register_guild(**default_guild) + + @commands.command() + @checks.guildowner() + @commands.guild_only() + async def runtimerole(self, ctx: commands.Context): + """Trigger the daily timerole""" + + await self.timerole_update() + await ctx.send("Success") + + @commands.group() + @checks.mod_or_permissions(administrator=True) + @commands.guild_only() + async def timerole(self, ctx): + """Adjust timerole settings""" + if ctx.invoked_subcommand is None: + await ctx.send_help() + + @timerole.command() + async def addrole(self, ctx: commands.Context, role: discord.Role, days: int, *requiredroles: discord.Role): + """Add a role to be added after specified time on server""" + guild = ctx.guild + + to_set = {'days': days} + if requiredroles: + to_set['required'] = [r.id for r in requiredroles] + + await self.config.guild(guild).roles.set_raw(role.id, value=to_set) + await ctx.send("Time Role for {0} set to {1} days".format(role.name, days)) + + @timerole.command() + async def channel(self, ctx: commands.Context, channel: discord.TextChannel): + """Sets the announce channel for role adds""" + guild = ctx.guild + + await self.config.guild(guild).announce.set(channel.id) + await ctx.send("Announce channel set to {0}".format(channel.mention)) + + @timerole.command() + async def removerole(self, ctx: commands.Context, role: discord.Role): + """Removes a role from being added after specified time""" + guild = ctx.guild + + await self.config.guild(guild).roles.set_raw(role.id, value=None) + await ctx.send("{0} will no longer be applied".format(role.name)) + + @timerole.command() + async def list(self, ctx: commands.Context): + """Lists all currently setup timeroles""" + guild = ctx.guild + + role_dict = await self.config.guild(guild).roles() + out = "" + for r_id, r_data in role_dict.items(): + if r_data is not None: + role = discord.utils.get(guild.roles, id=int(r_id)) + r_roles = [] + if role is None: + role = r_id + if 'required' in r_data: + r_roles = [str(discord.utils.get(guild.roles, id=int(new_id))) for new_id in r_data['required']] + out += "{} || {} days || requires: {}\n".format(str(role), r_data['days'], r_roles) + await ctx.maybe_send_embed(out) + + async def timerole_update(self): + for guild in self.bot.guilds: + addlist = [] + + role_dict = await self.config.guild(guild).roles() + if not any(role_data for role_data in role_dict.values()): # No roles + continue + + for member in guild.members: + has_roles = [r.id for r in member.roles] + + get_roles = [int(rID) for rID, r_data in role_dict.items() if r_data is not None] + + check_roles = set(get_roles) - set(has_roles) + + for role_id in check_roles: + # Check for required role + if 'required' in role_dict[str(role_id)]: + if not set(role_dict[str(role_id)]['required']) & set(has_roles): + # Doesn't have required role + continue + + if member.joined_at + timedelta( + days=role_dict[str(role_id)]['days']) <= datetime.today(): + # Qualifies + addlist.append((member, role_id)) + + channel = await self.config.guild(guild).announce() + if channel is not None: + channel = guild.get_channel(channel) + + title = "**These members have received the following roles**\n" + results = "" + for member, role_id in addlist: + role = discord.utils.get(guild.roles, id=role_id) + await member.add_roles(role, reason="Timerole") + results += "{} : {}\n".format(member.display_name, role.name) + + if channel is not None and results: + await channel.send(title) + for page in pagify( + results, shorten_by=50): + await channel.send(page) + + async def check_day(self): + while self is self.bot.get_cog("Timerole"): + tomorrow = datetime.now() + timedelta(days=1) + midnight = datetime(year=tomorrow.year, month=tomorrow.month, + day=tomorrow.day, hour=0, minute=0, second=0) + + await asyncio.sleep((midnight - datetime.now()).seconds) + + await self.timerole_update() + + await asyncio.sleep(3) + # then start loop over again