diff --git a/kdb-bot/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json index 2c88a59e..ea3b84f3 100644 --- a/kdb-bot/src/bot/translation/de.json +++ b/kdb-bot/src/bot/translation/de.json @@ -161,25 +161,36 @@ "max_char_count_exceeded": "Der Text darf nicht mehr als 128 Zeichen lang sein!" }, "user": { + "atr": { + "id": "Id", + "name": "Name", + "discord_join": "Discord beigetreten am", + "last_join": "Server beigetreten am", + "xp": "XP", + "ontime": "Ontime", + "roles": "Rollen", + "joins": "Beitritte", + "lefts": "Abgänge", + "warnings": "Verwarnungen" + }, "info": { - "fields": { - "id": "Id", - "name": "Name", - "discord_join": "Discord beigetreten am", - "last_join": "Server beigetreten am", - "xp": "XP", - "ontime": "Ontime", - "roles": "Rollen", - "joins": "Beitritte", - "lefts": "Abgänge", - "warnings": "Verwarnungen" - }, "footer": "" }, "get": { - "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(", "xp": "{} hat {} xp", "ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal" + }, + "set": { + "xp": "{} hat nun {} xp", + "error": { + "value_type_not_numeric": "Der angegebende Wert ist keine Ganzzahl! :(", + "type_error": "Der angegebene Wert konnte nicht als eine Ganzzahl interpretiert werden :(", + "database_error": "Beim Speichern des Wertes kam es zu einem Fehler :(", + "general_error": "Bei der Ausführung dieses Befehls kam es zu einen Fehler :(" + } + }, + "error": { + "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(" } } }, diff --git a/kdb-bot/src/modules/base/command/user_group.py b/kdb-bot/src/modules/base/command/user_group.py index 077a32d3..a919f3f7 100644 --- a/kdb-bot/src/modules/base/command/user_group.py +++ b/kdb-bot/src/modules/base/command/user_group.py @@ -2,12 +2,14 @@ from typing import Optional, List import discord from cpl_core.configuration import ConfigurationABC +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 +from mysql.connector.errors import DatabaseError from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.message_service_abc import MessageServiceABC @@ -18,6 +20,7 @@ from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC from bot_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC from bot_data.abc.user_repository_abc import UserRepositoryABC +from modules.level.service.level_service import LevelService from modules.permission.abc.permission_service_abc import PermissionServiceABC @@ -32,11 +35,13 @@ class UserGroup(DiscordCommandABC): client_utils: ClientUtilsServiceABC, permissions: PermissionServiceABC, servers: ServerRepositoryABC, + db: DatabaseContextABC, users: UserRepositoryABC, user_joined_servers: UserJoinedServerRepositoryABC, user_joined_voice_channel: UserJoinedVoiceChannelRepositoryABC, translate: TranslatePipe, - date: DateTimeOffsetPipe + date: DateTimeOffsetPipe, + level: LevelService ): DiscordCommandABC.__init__(self) @@ -47,14 +52,21 @@ class UserGroup(DiscordCommandABC): self._client_utils = client_utils self._permissions = permissions self._servers = servers + self._db = db self._users = users self._user_joined_servers = user_joined_servers self._user_joined_voice_channel = user_joined_voice_channel self._t = translate self._date = date + self._level = level self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}') + self._atr_dict = { + "xp": self._t.transform('modules.base.user.atr.xp'), + 'ontime': self._t.transform('modules.base.user.atr.ontime') + } + @commands.hybrid_group() @commands.guild_only() async def user(self, ctx: Context): @@ -87,25 +99,25 @@ class UserGroup(DiscordCommandABC): ontime = self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id).sum( lambda join: round((join.leaved_on - join.joined_on).total_seconds() / 3600, 2)) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.id'), value=member.id) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.name'), value=member.name) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.discord_join'), + embed.add_field(name=self._t.transform('modules.base.user.atr.id'), value=member.id) + embed.add_field(name=self._t.transform('modules.base.user.atr.name'), value=member.name) + embed.add_field(name=self._t.transform('modules.base.user.atr.discord_join'), value=self._date.transform(member.created_at), inline=False) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.last_join'), + embed.add_field(name=self._t.transform('modules.base.user.atr.last_join'), value=self._date.transform(member.joined_at), inline=False) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.xp'), value=str(user.xp)) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.ontime'), value=str(ontime)) + embed.add_field(name=self._t.transform('modules.base.user.atr.xp'), value=str(user.xp)) + embed.add_field(name=self._t.transform('modules.base.user.atr.ontime'), value=str(ontime)) roles = '' for role in member.roles: roles += f'{role.name}\n' - embed.add_field(name=self._t.transform('modules.base.user.info.fields.roles'), value=roles, inline=False) + embed.add_field(name=self._t.transform('modules.base.user.atr.roles'), value=roles, inline=False) if is_mod or member == ctx.author: joins_string = '' for join in joins: joins_string += f'{self._date.transform(join.joined_on)}\n' - embed.add_field(name=self._t.transform('modules.base.user.info.fields.joins'), value=joins_string) + embed.add_field(name=self._t.transform('modules.base.user.atr.joins'), value=joins_string) if is_mod or member == ctx.author: lefts_string = '' @@ -116,10 +128,10 @@ class UserGroup(DiscordCommandABC): continue lefts_string += f'{self._date.transform(join.leaved_on)}\n' - embed.add_field(name=self._t.transform('modules.base.user.info.fields.lefts'), value=lefts_string) + embed.add_field(name=self._t.transform('modules.base.user.atr.lefts'), value=lefts_string) if is_mod or member == ctx.author: - embed.add_field(name=self._t.transform('modules.base.user.info.fields.warnings'), + embed.add_field(name=self._t.transform('modules.base.user.atr.warnings'), value=self._t.transform('common.not_implemented_yet'), inline=False) # send to interaction because of sensitive data @@ -130,7 +142,7 @@ class UserGroup(DiscordCommandABC): @commands.guild_only() @CommandChecks.check_is_ready() async def get(self, ctx: Context, atr: str, member: discord.Member = None): - self._logger.debug(__name__, f'Received command user-info {ctx}:{member}') + self._logger.debug(__name__, f'Received command user-get {ctx}:{member}') is_mod = self._permissions.is_member_moderator(ctx.author) if member is not None and not is_mod: @@ -143,20 +155,19 @@ class UserGroup(DiscordCommandABC): server = self._servers.find_server_by_discord_id(ctx.guild.id) user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) - match atr: - case 'xp': - value = str(user.xp) - - case 'ontime': - value = str(round( - self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id) - .sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600), - 2 - )) + if atr == self._atr_dict["xp"]: + value = str(user.xp) - case other: - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.get.atr_not_found').format(atr)) - return + elif atr == self._atr_dict["ontime"]: + value = str(round( + self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id) + .sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600), + 2 + )) + + else: + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr)) + return await self._message_service.send_interaction_msg( ctx.interaction, @@ -165,5 +176,51 @@ class UserGroup(DiscordCommandABC): @get.autocomplete('atr') async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: - atr_list = ['xp', 'ontime'] + atr_list = [self._atr_dict["xp"], self._atr_dict["ontime"]] + return [app_commands.Choice(name=atr, value=atr) for atr in atr_list] + + @user.command() + @commands.guild_only() + @CommandChecks.check_is_ready() + @CommandChecks.check_is_member_moderator() + async def set(self, ctx: Context, atr: str, value: str, member: discord.Member = None): + self._logger.debug(__name__, f'Received command user-set {ctx}:{member}') + + if member is None or not isinstance(member, discord.Member): + member = ctx.author + + server = self._servers.find_server_by_discord_id(ctx.guild.id) + user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) + + if atr == self._atr_dict["xp"]: + if not value.isnumeric(): + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( + 'modules.base.user.set.error.value_type_not_numeric')) + return + + try: + user.xp = int(value) + except TypeError as te: + self._logger.error(__name__, f'String value couldn\'t be converted to int', te) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( + 'modules.base.user.set.error.type_error')) + return + else: + self._users.update_user(user) + self._db.save_changes() + await self._level.check_level(member) + + else: + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( + 'modules.base.user.error.atr_not_found').format(atr)) + return + + await self._message_service.send_interaction_msg( + ctx.interaction, + self._t.transform(f'modules.base.user.set.{atr}').format(member.mention, value) + ) + + @set.autocomplete('atr') + async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: + atr_list = [self._atr_dict["xp"]] return [app_commands.Choice(name=atr, value=atr) for atr in atr_list]