diff --git a/kdb-bot/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json index 18549e58..92874768 100644 --- a/kdb-bot/src/bot/translation/de.json +++ b/kdb-bot/src/bot/translation/de.json @@ -45,6 +45,30 @@ "no_entry_point_error": "Fehler: Kein Eintrittspunkt!", "extension_failed": "Fehler: Erweiterung ist fehlgeschlagen!", "bot_not_ready_yet": "Ey Alter! Gedulde dich doch mal! ..." + }, + "colors": { + "blue": "Blau", + "dark_blue": "Dunkelblau", + "dark_gold": "Dunkelgold", + "dark_gray": "Dunkelgrau", + "dark_green": "Dunkelgrün", + "dark_grey": "Dunkelgrau", + "dark_magenta": "Dunkelmagenta", + "dark_orange": "Dunkelorange", + "dark_purple": "Dunkelviolett", + "dark_red": "Dunkelrot", + "dark_teal": "Dunkelblaugrün", + "default": "Standard", + "gold": "Gold", + "green": "Grün", + "greyple": "Graugrün", + "light_gray": "Hellgrau", + "magenta": "Magenta", + "orange": "Orange", + "purple": "Violett", + "red": "Rot", + "teal": "Blaugrün", + "yellow": "Gelb" } }, "modules": { @@ -152,7 +176,9 @@ "level": { "new_level_message": "<@{}> ist nun Level {}", "error": { - "nothing_found": "Keine auto-role Einträge gefunden." + "nothing_found": "Keine Level Einträge gefunden.", + "level_with_name_already_exists": "Ein Level mit dem Namen {} existiert bereits!", + "level_with_xp_already_exists": "Das Level {} hat bereits die Mindest XP {}!" }, "list": { "title": "Level:", @@ -160,6 +186,12 @@ "name": "Name", "min_xp": "Mindest XP", "permission_int": "Berechtigungen" + }, + "create": { + "created": "Level {} mit Berechtigungen {} wurde erstellt.", + "seeding_started": "Levelsystem wird neu geladen.", + "seeding_failed": "Levelsystem konnte nicht neu geladen werden.", + "seeding_finished": "Levelsystem wurde Erfolgreich neu geladen." } }, "database": {}, diff --git a/kdb-bot/src/modules/level/command/level_group.py b/kdb-bot/src/modules/level/command/level_group.py index 8de28aa4..0eaf7d35 100644 --- a/kdb-bot/src/modules/level/command/level_group.py +++ b/kdb-bot/src/modules/level/command/level_group.py @@ -1,8 +1,11 @@ +from typing import List as TList + import discord from cpl_core.database.context import DatabaseContextABC from cpl_discord.command import DiscordCommandABC from cpl_discord.service import DiscordBotServiceABC from cpl_translation import TranslatePipe +from discord import app_commands from discord.ext import commands from discord.ext.commands import Context @@ -11,6 +14,9 @@ from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.logging.command_logger import CommandLogger from bot_data.abc.level_repository_abc import LevelRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC +from bot_data.model.level import Level +from modules.level.level_seeder import LevelSeeder +from modules.level.service.level_service import LevelService from modules.permission.abc.permission_service_abc import PermissionServiceABC @@ -27,6 +33,8 @@ class LevelGroup(DiscordCommandABC): db_context: DatabaseContextABC, levels: LevelRepositoryABC, servers: ServerRepositoryABC, + level_service: LevelService, + level_seeder: LevelSeeder, ): DiscordCommandABC.__init__(self) @@ -40,6 +48,9 @@ class LevelGroup(DiscordCommandABC): self._levels = levels self._servers = servers + self._level_service = level_service + self._level_seeder = level_seeder + self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}') @commands.hybrid_group() @@ -87,3 +98,88 @@ class LevelGroup(DiscordCommandABC): embed.add_field(name=self._t.transform('modules.level.list.permission_int'), value=permissions, inline=True) await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait) self._logger.trace(__name__, f'Finished command level list') + + @level.command() + @commands.guild_only() + async def create(self, ctx: Context, name: str, color: str, min_xp: int, permissions: int): + self._logger.debug(__name__, f'Received command level create {ctx}') + + try: + color = hex(discord.Colour.from_str(color).value) + except Exception as e: + self._logger.error(__name__, f'Error parsing color {color}', e) + return + + try: + permissions = discord.Permissions(permissions).value + except Exception as e: + self._logger.error(__name__, f'Error parsing permissions {permissions}', e) + return + + if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx): + return + + if ctx.guild is None: + return + + server = self._servers.get_server_by_discord_id(ctx.guild.id) + level = Level(name, color, min_xp, permissions, server) + levels = self._levels.get_levels_by_server_id(server.server_id) + + if levels.where(lambda l: l.name == level.name).first_or_default() is not None: + self._logger.debug(__name__, f'Level with name {level.name} already exists') + await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.error.level_with_name_already_exists').format(level.name)) + elif levels.where(lambda l: l.min_xp == level.min_xp).first_or_default() is not None: + self._logger.debug(__name__, f'Level with min_xp {level.min_xp} already exists {level.name}') + found_level = levels.where(lambda l: l.min_xp == level.min_xp).first_or_default() + await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.error.level_with_xp_already_exists').format(found_level.name, found_level.min_xp)) + else: + try: + self._levels.add_level(level) + self._db_context.save_changes() + self._logger.info(__name__, f'Saved level {name} with color {color}, min_xp {min_xp} and permissions {permissions}') + except Exception as e: + self._logger.error(__name__, f'Could not save level {name} with color {color}, min_xp {min_xp} and permissions {permissions}', e) + else: + await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.create.created').format(name, permissions)) + + # send message to ctx.channel because send_ctx_msg resolves ctx + try: + await self._message_service.send_channel_message(ctx.channel, self._t.transform('modules.level.create.seeding_started')) + await self._level_seeder.seed() + await self._message_service.send_channel_message(ctx.channel, self._t.transform('modules.level.create.seeding_finished')) + except Exception as e: + self._logger.error(__name__, f'Level seeding failed', e) + await self._message_service.send_channel_message(ctx.channel, self._t.transform('modules.level.create.seeding_failed')) + + self._logger.trace(__name__, f'Finished command level create') + + @create.autocomplete('color') + async def create_color_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]: + colors = [ + ('blue', discord.Colour.blue().to_rgb()), + ('dark_blue', discord.Colour.dark_blue().to_rgb()), + ('dark_gold', discord.Colour.dark_gold().to_rgb()), + ('dark_gray', discord.Colour.dark_gray().to_rgb()), + ('dark_green', discord.Colour.dark_green().to_rgb()), + ('dark_grey', discord.Colour.dark_grey().to_rgb()), + ('dark_magenta', discord.Colour.dark_magenta().to_rgb()), + ('dark_orange', discord.Colour.dark_orange().to_rgb()), + ('dark_purple', discord.Colour.dark_purple().to_rgb()), + ('dark_red', discord.Colour.dark_red().to_rgb()), + ('dark_teal', discord.Colour.dark_teal().to_rgb()), + ('default', discord.Colour.default().to_rgb()), + ('gold', discord.Colour.gold().to_rgb()), + ('green', discord.Colour.green().to_rgb()), + ('greyple', discord.Colour.greyple().to_rgb()), + ('light_grey', discord.Colour.light_grey().to_rgb()), + ('magenta', discord.Colour.magenta().to_rgb()), + ('orange', discord.Colour.orange().to_rgb()), + ('purple', discord.Colour.purple().to_rgb()), + ('red', discord.Colour.red().to_rgb()), + ('teal', discord.Colour.teal().to_rgb()), + ('yellow', discord.Colour.yellow().to_rgb()) + ] + # value in rg format see: + # https://discordpy.readthedocs.io/en/latest/api.html#discord.Colour.to_rgb + return [app_commands.Choice(name=self._t.transform(f'common.colors.{color}'), value=f'rgb({code[0]}, {code[1]}, {code[2]})') for color, code in colors] diff --git a/kdb-bot/src/modules/level/level_seeder.py b/kdb-bot/src/modules/level/level_seeder.py index 9a1148bb..870a7b30 100644 --- a/kdb-bot/src/modules/level/level_seeder.py +++ b/kdb-bot/src/modules/level/level_seeder.py @@ -1,3 +1,4 @@ +import discord from cpl_discord.container import Guild, Role from cpl_discord.service import DiscordBotServiceABC from cpl_query.extension import List @@ -26,14 +27,20 @@ class LevelSeeder(DataSeederABC): self._default_levels = levels.levels.order_by_descending(lambda l: l.min_xp) async def _create_level(self, level: Level, guild: Guild, server: Server): + level.server = server try: if guild.roles.where(lambda r: r.name == level.name).first_or_default() is not None: return await guild.create_role(name=level.name, colour=Colour(int(level.color, 16)), hoist=False, mentionable=True, permissions=Permissions(level.permissions)) self._logger.info(__name__, f'Created level {level.name}') - level.server = server - self._levels.add_level(level) + + if self._levels.find_levels_by_server_id(server.server_id).where(lambda l: l == level).first_or_default() is not None: + self._levels.add_level(level) + except discord.errors.Forbidden as e: + self._logger.error(__name__, f'Creating level failed', e) + level.permissions = 0 + self._levels.update_level(level) except Exception as e: self._logger.error(__name__, f'Creating level failed', e) @@ -66,6 +73,7 @@ class LevelSeeder(DataSeederABC): if created_default: continue + levels = levels.order_by_descending(lambda l: l.min_xp) position_above_levels = guild.roles.where(lambda r: r.name == self._level_header).single().position for role in guild.roles.order_by_descending(lambda r: r.position): if levels.where(lambda l: l.name == role.name).count() == 0: diff --git a/kdb-bot/src/modules/level/service/level_service.py b/kdb-bot/src/modules/level/service/level_service.py index bf53b11c..f47102b9 100644 --- a/kdb-bot/src/modules/level/service/level_service.py +++ b/kdb-bot/src/modules/level/service/level_service.py @@ -76,7 +76,7 @@ class LevelService: level_settings: LevelServerSettings = self._config.get_configuration(f'LevelServerSettings_{guild.id}') await self._message_service.send_channel_message( self._bot.get_channel(level_settings.changed_level_notification_channel), - self._t.transform('modules.level.new_level_message'.format(member.id, level.name)), + self._t.transform('modules.level.new_level_message').format(member.id, level.name), is_persistent=True )