diff --git a/src/modules/ranks/ui/overview.py b/src/modules/ranks/ui/overview.py index f9cfbcd6..b551ee58 100644 --- a/src/modules/ranks/ui/overview.py +++ b/src/modules/ranks/ui/overview.py @@ -20,6 +20,7 @@ from ..data import AnyRankData, RankData from ..utils import rank_model_from_type, format_stat_range, stat_data_to_value from .editor import RankEditor from .preview import RankPreviewUI +from .templates import get_guild_template _p = babel._p @@ -87,7 +88,73 @@ class RankOverviewUI(MessageUI): Ranks are determined by rank type. """ - await press.response.send_message("Not Implemented Yet") + t = self.bot.translator.t + + # Prevent role creation spam + if await self.rank_model.table.select_where(guildid=self.guild.id): + return await press.response.send_message(content=t(_p( + 'ui:rank_overview|button:auto|error:already_created', + "The rank roles have already been created!" + )), ephemeral=True) + + await press.response.defer(thinking=True) + + if not self.guild.me.guild_permissions.manage_roles: + raise SafeCancellation(t(_p( + 'ui:rank_overview|button:auto|error:my_permissions', + "I lack the 'Manage Roles' permission required to create rank roles!" + ))) + + # Get rank role template based on set RankType and VoiceMode + template = get_guild_template(self.rank_type, self.lguild.guild_mode.voice) + if not template: + # Safely error if rank type or voice mode isn't an expected value + raise SafeCancellation(t(_p( + 'ui:rank_overview|button:auto|error:invalid_template', + "Unable to determine rank role template!"))) + + roles = [] + async with self.cog.ranklock(self.guild.id): + for rank in reversed(template): + try: + colour = discord.Colour.from_str(rank.colour) + role = await self.guild.create_role(name=t(rank.name), colour=colour) + roles.append(role) + await self.rank_model.create( + roleid=role.id, + guildid=self.guild.id, + required=rank.required, + reward=rank.reward, + message=t(rank.message) + ) + self.cog.flush_guild_ranks(self.guild.id) + + # Error if manage roles is lost during the process. This shouldn't happen + except discord.Forbidden: + self.cog.flush_guild_ranks(self.guild.id) + raise SafeCancellation(t(_p( + 'ui:rank_overview|button|auto|role_creation|error:forbidden', + "An error occurred while autocreating rank roles!\n" + "I lack the 'Manage Roles' permission required to create rank roles!" + ))) + + except discord.HTTPException: + self.cog.flush_guild_ranks(self.guild.id) + raise SafeCancellation(t(_p( + 'ui:rank_overview|button:auto|role_creation|error:unknown', + "An error occurred while autocreating rank roles!\n" + "Please check the server has enough space for new roles " + "and try again." + ))) + + success_msg = t(_p( + 'ui:rank_overview|button:auto|role_creation|success', + "Successfully created the following rank roles:\n{roles}" + )).format(roles="\n".join(role.mention for role in roles)) + embed = discord.Embed( + colour=discord.Colour.brand_green(), + description=success_msg) + await press.edit_original_response(embed=embed) async def auto_button_refresh(self): self.auto_button.label = self.bot.translator.t(_p( @@ -384,11 +451,17 @@ class RankOverviewUI(MessageUI): # No ranks, give hints about adding ranks desc = t(_p( 'ui:rank_overview|embed:noranks|desc', - "No activity ranks have been set up!\n" - "Press 'AUTO' to automatically create a " - "standard heirachy of voice | text | xp ranks, " - "or select a role or press Create below!" + "No activity ranks have been set up!" )) + if show_note: + auto_addendum = t(_p( + 'ui:rank_overview|embed:noranks|desc|admin_addendum', + "Press 'Auto Create' to automatically create a " + "standard heirachy of ranks.\n" + "To manually create ranks, press 'Create Rank' below, or select a role!" + )) + desc = "\n".join((desc, auto_addendum)) + if self.rank_type is RankType.VOICE: title = t(_p( 'ui:rank_overview|embed|title|type:voice', diff --git a/src/modules/ranks/ui/templates.py b/src/modules/ranks/ui/templates.py new file mode 100644 index 00000000..99d836d2 --- /dev/null +++ b/src/modules/ranks/ui/templates.py @@ -0,0 +1,303 @@ +from collections import namedtuple +from core.data import RankType +from core.lion_guild import VoiceMode + +from meta import conf, LionBot +from babel.translator import ctx_translator + +from .. import babel + +_p = babel._p + +RankBase = namedtuple("RankBase", ("name", "required", "reward", "message", "colour")) + +""" +Reward message defaults +""" + +voice_reward_msg = _p( + 'ui:rank_editor|input:message|default|type:voice', + "Congratulations {user_mention}!\n" + "For working hard for **{requires}**, you have achieved the rank of " + "**{role_name}** in **{guild_name}**! Keep up the good work." +) + +xp_reward_msg = _p( + 'ui:rank_editor|input:message|default|type:xp', + "Congratulations {user_mention}!\n" + "For earning **{requires}**, you have achieved the guild rank of " + "**{role_name}** in **{guild_name}**!" +) + +msg_reward_msg = _p( + 'ui:rank_editor|input:message|default|type:msg', + "Congratulations {user_mention}!\n" + "For sending **{requires}**, you have achieved the guild rank of " + "**{role_name}** in **{guild_name}**!" +) + + +""" +Rank templates based on voice activity +""" + +study_voice_template = [ + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:1', + "Voice Level 1 (1h)"), + required=3600, + reward=1000, + message=voice_reward_msg, + colour="#1f28e2" + ), + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:2', + "Voice Level 2 (3h)"), + required=10800, + reward=2000, + message=voice_reward_msg, + colour="#006bff" + ), + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:3', + "Voice Level 3 (6h)"), + required=21600, + reward=3000, + message=voice_reward_msg, + colour="#0091ff" + ), + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:4', + "Voice Level 4 (10h)"), + required=36000, + reward=4000, + message=voice_reward_msg, + colour="#00adf5" + ), + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:5', + "Voice Level 5 (20h)"), + required=72000, + reward=5000, + message=voice_reward_msg, + colour="#00c6bf" + ), + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:6', + "Voice Level 6 (40h)"), + required=144000, + reward=6000, + message=voice_reward_msg, + colour="#00db86" + ), + RankBase( + name=_p('rank_autocreate|template|type:study_voice|level:7', + "Voice Level 7 (80h)"), + required=288000, + reward=7000, + message=voice_reward_msg, + colour="#7cea5a" + ) +] + +general_voice_template = [ + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:1', + "Voice Level 1 (1h)"), + required=3600, + reward=1000, + message=voice_reward_msg, + colour="#1f28e2" + ), + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:2', + "Voice Level 2 (2h)"), + required=7200, + reward=2000, + message=voice_reward_msg, + colour="#006bff" + ), + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:3', + "Voice Level 3 (4h)"), + required=14400, + reward=3000, + message=voice_reward_msg, + colour="#0091ff" + ), + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:4', + "Voice Level 4 (8h)"), + required=28800, + reward=4000, + message=voice_reward_msg, + colour="#00adf5" + ), + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:5', + "Voice Level 5 (16h)"), + required=57600, + reward=5000, + message=voice_reward_msg, + colour="#00c6bf" + ), + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:6', + "Voice Level 6 (32h)"), + required=115200, + reward=6000, + message=voice_reward_msg, + colour="#00db86" + ), + RankBase( + name=_p('rank_autocreate|template|type:general_voice|level:7', + "Voice Level 7 (64h)"), + required=230400, + reward=7000, + message=voice_reward_msg, + colour="#7cea5a" + ) +] + +""" +Rank templates based on message XP earned +""" + +xp_template = [ + RankBase( + name=_p('rank_autocreate|template|type:xp|level:1', + "XP Level 1 (2000)"), + required=2000, + reward=1000, + message=xp_reward_msg, + colour="#1f28e2" + ), + RankBase( + name=_p('rank_autocreate|template|type:xp|level:2', + "XP Level 2 (4000)"), + required=4000, + reward=2000, + message=xp_reward_msg, + colour="#006bff" + ), + RankBase( + name=_p('rank_autocreate|template|type:xp|level:3', + "XP Level 3 (8000)"), + required=8000, + reward=3000, + message=xp_reward_msg, + colour="#0091ff" + ), + RankBase( + name=_p('rank_autocreate|template|type:xp|level:4', + "XP Level 4 (16000)"), + required=16000, + reward=4000, + message=xp_reward_msg, + colour="#00adf5" + ), + RankBase( + name=_p('rank_autocreate|template|type:xp|level:5', + "XP Level 5 (32000)"), + required=32000, + reward=5000, + message=xp_reward_msg, + colour="#00c6bf" + ), + RankBase( + name=_p('rank_autocreate|template|type:xp|level:6', + "XP Level 6 (64000)"), + required=64000, + reward=6000, + message=xp_reward_msg, + colour="#00db86" + ), + RankBase( + name=_p('rank_autocreate|template|type:xp|level:7', + "XP Level 7 (128000)"), + required=128000, + reward=7000, + message=xp_reward_msg, + colour="#7cea5a" + ) +] + +""" +Rank templates based on messages sent +""" + +msg_template = [ + RankBase( + name=_p('rank_autocreate|template|type:msg|level:1', + "Message Level 1 (200)"), + required=200, + reward=1000, + message=msg_reward_msg, + colour="#1f28e2" + ), + RankBase( + name=_p('rank_autocreate|template|type:msg|level:2', + "Message Level 2 (400)"), + required=400, + reward=2000, + message=msg_reward_msg, + colour="#006bff" + ), + RankBase( + name=_p('rank_autocreate|template|type:msg|level:3', + "Message Level 3 (800)"), + required=800, + reward=3000, + message=msg_reward_msg, + colour="#0091ff" + ), + RankBase( + name=_p('rank_autocreate|template|type:msg|level:4', + "Message Level 4 (1600)"), + required=1600, + reward=4000, + message=msg_reward_msg, + colour="#00adf5" + ), + RankBase( + name=_p('rank_autocreate|template|type:msg|level:5', + "Message Level 5 (3200)"), + required=3200, + reward=5000, + message=msg_reward_msg, + colour="#00c6bf" + ), + RankBase( + name=_p('rank_autocreate|template|type:msg|level:6', + "Message Level 6 (6400)"), + required=6400, + reward=6000, + message=msg_reward_msg, + colour="#00db86" + ), + RankBase( + name=_p('rank_autocreate|template|type:msg|level:7', + "Message Level 7 (12800)"), + required=12800, + reward=7000, + message=msg_reward_msg, + colour="#7cea5a" + ) +] + + +def get_guild_template(rank_type: RankType, voice_mode: VoiceMode): + """ + Returns the best fit rank template + based on the guild's rank type and voice mode. + """ + if rank_type == RankType.VOICE: + if voice_mode == VoiceMode.STUDY: + return study_voice_template + if voice_mode == VoiceMode.VOICE: + return general_voice_template + if rank_type == RankType.XP: + return xp_template + if rank_type == RankType.MESSAGE: + return msg_template + return None