diff --git a/kdb-bot/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json index 0768197a..58bb23d4 100644 --- a/kdb-bot/src/bot/translation/de.json +++ b/kdb-bot/src/bot/translation/de.json @@ -199,7 +199,8 @@ "stats": { "list": { "statistic": "Statistik", - "description": "Beschreibung" + "description": "Beschreibung", + "nothing_found": "Keine Statistiken gefunden." }, "view": { "statistic": "Statistik", @@ -213,6 +214,10 @@ "edit": { "failed": "Statistik kann nicht bearbeitet werden :(", "success": "Statistik wurde gespeichert :D" + }, + "remove": { + "failed": "Statistik kann nicht gelöscht werden :(", + "success": "Statistik wurde gelöscht :D" } } }, diff --git a/kdb-bot/src/bot_data/data_module.py b/kdb-bot/src/bot_data/data_module.py index 0668bffe..e32d8039 100644 --- a/kdb-bot/src/bot_data/data_module.py +++ b/kdb-bot/src/bot_data/data_module.py @@ -11,6 +11,7 @@ from bot_data.abc.client_repository_abc import ClientRepositoryABC from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC from bot_data.abc.level_repository_abc import LevelRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC +from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC 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 @@ -21,6 +22,7 @@ from bot_data.service.known_user_repository_service import KnownUserRepositorySe from bot_data.service.level_repository_service import LevelRepositoryService from bot_data.service.seeder_service import SeederService from bot_data.service.server_repository_service import ServerRepositoryService +from bot_data.service.statistic_repository_service import StatisticRepositoryService from bot_data.service.user_joined_server_repository_service import UserJoinedServerRepositoryService from bot_data.service.user_joined_voice_channel_service import UserJoinedVoiceChannelRepositoryService from bot_data.service.user_repository_service import UserRepositoryService @@ -44,5 +46,6 @@ class DataModule(ModuleABC): services.add_transient(UserJoinedVoiceChannelRepositoryABC, UserJoinedVoiceChannelRepositoryService) services.add_transient(AutoRoleRepositoryABC, AutoRoleRepositoryService) services.add_transient(LevelRepositoryABC, LevelRepositoryService) + services.add_transient(StatisticRepositoryABC, StatisticRepositoryService) services.add_transient(SeederService) diff --git a/kdb-bot/src/bot_data/model/statistic.py b/kdb-bot/src/bot_data/model/statistic.py index 1c34a264..11011237 100644 --- a/kdb-bot/src/bot_data/model/statistic.py +++ b/kdb-bot/src/bot_data/model/statistic.py @@ -1,7 +1,7 @@ from datetime import datetime -from typing import Optional from cpl_core.database import TableABC +from cpl_core.utils import CredentialManager from bot_data.model.server import Server @@ -12,7 +12,7 @@ class Statistic(TableABC): self._id = id self._name = name self._description = description - self._code = code + self._code = CredentialManager.encrypt(code) self._server = server TableABC.__init__(self) @@ -37,11 +37,11 @@ class Statistic(TableABC): @property def code(self) -> str: - return self._code + return CredentialManager.decrypt(self._code) @code.setter def code(self, value: str): - self._code = value + self._code = CredentialManager.encrypt(value) @property def server(self) -> Server: @@ -64,7 +64,8 @@ class Statistic(TableABC): def get_select_by_name_string(name: str, s_id: int) -> str: return str(f""" SELECT * FROM `Statistics` - WHERE `Name` = {name}; + WHERE `ServerId` = {s_id} + AND `Name` = '{name}'; """) @staticmethod @@ -93,9 +94,9 @@ class Statistic(TableABC): def udpate_string(self) -> str: return str(f""" UPDATE `Statistics` - SET `Name` = {self._name}, - `Description` = '{self._description}' - `Code` = '{self._code}' + SET `Name` = '{self._name}', + `Description` = '{self._description}', + `Code` = '{self._code}', `LastModifiedAt` = '{self._modified_at}' WHERE `Id` = {self._id}; """) diff --git a/kdb-bot/src/bot_data/service/statistic_repository_service.py b/kdb-bot/src/bot_data/service/statistic_repository_service.py index 222bdf38..8f31dbe2 100644 --- a/kdb-bot/src/bot_data/service/statistic_repository_service.py +++ b/kdb-bot/src/bot_data/service/statistic_repository_service.py @@ -1,6 +1,7 @@ from typing import Optional from cpl_core.database.context import DatabaseContextABC +from cpl_core.utils import CredentialManager from cpl_query.extension import List from bot_core.logging.database_logger import DatabaseLogger @@ -27,10 +28,14 @@ class StatisticRepositoryService(StatisticRepositoryABC): return value def _statistic_from_result(self, sql_result: tuple) -> Statistic: + code = self._get_value_from_result(sql_result[3]) + if code is not None: + code = CredentialManager.decrypt(code) + statistic = Statistic( self._get_value_from_result(sql_result[1]), self._get_value_from_result(sql_result[2]), - self._get_value_from_result(sql_result[3]), + code, self._statistics.get_server_by_id(sql_result[4]), id=self._get_value_from_result(sql_result[0]) ) diff --git a/kdb-bot/src/modules/stats/command/stats_group.py b/kdb-bot/src/modules/stats/command/stats_group.py index 0d61f249..96734119 100644 --- a/kdb-bot/src/modules/stats/command/stats_group.py +++ b/kdb-bot/src/modules/stats/command/stats_group.py @@ -1,9 +1,8 @@ -import textwrap from typing import List as TList import discord +from cpl_core.database.context import DatabaseContextABC from cpl_discord.command import DiscordCommandABC -from cpl_query.extension import List from cpl_translation import TranslatePipe from discord import app_commands from discord.ext import commands @@ -13,29 +12,11 @@ from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.logging.command_logger import CommandLogger from bot_data.abc.server_repository_abc import ServerRepositoryABC -from bot_data.model.statistic import Statistic +from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC from modules.permission.abc.permission_service_abc import PermissionServiceABC from modules.stats.service.statistic_service import StatisticService from modules.stats.ui.add_statistic_form import AddStatisticForm -stats = List(Statistic, [ - Statistic( - 'Benutzer XP Aufsteigend', - 'Zeigt XP von jedem Benutzer, aufsteigend nach XP', - textwrap.dedent("""\ - result.header.append('Name') - result.header.append('XP') - - for user in users.order_by(lambda u: u.xp): - row = List(str) - member = guild.get_member(user.discord_id) - row.append(member.name) - row.append(str(user.xp)) - result.values.append(row) - """)), - Statistic('Benutzer XP Absteigend', 'Zeigt XP von jedem Benutzer, absteigend nach XP', '') -]) - class StatsGroup(DiscordCommandABC): @@ -48,6 +29,8 @@ class StatsGroup(DiscordCommandABC): permission_service: PermissionServiceABC, statistic: StatisticService, servers: ServerRepositoryABC, + stats: StatisticRepositoryABC, + db: DatabaseContextABC, ): DiscordCommandABC.__init__(self) @@ -58,6 +41,8 @@ class StatsGroup(DiscordCommandABC): self._permissions = permission_service self._statistic = statistic self._servers = servers + self._stats = stats + self._db = db @commands.hybrid_group() @commands.guild_only() @@ -76,17 +61,27 @@ class StatsGroup(DiscordCommandABC): self._logger.trace(__name__, f'Finished command stats list') return + if ctx.guild is None: + return + embed = discord.Embed( title=self._t.transform('modules.auto_role.list.title'), description=self._t.transform('modules.auto_role.list.description'), color=int('ef9d0d', 16) ) + server = self._servers.get_server_by_discord_id(ctx.guild.id) + stats = self._stats.get_statistics_by_server_id(server.server_id) + + if stats.count() == 0: + await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.stats.list.nothing_found')) + return + statistics = '' descriptions = '' for statistic in stats: - statistics += f'\n{statistic["Name"]}' - descriptions += f'\n{statistic["Description"]}' + statistics += f'\n{statistic.name}' + descriptions += f'\n{statistic.description}' embed.add_field(name=self._t.transform('modules.stats.list.statistic'), value=statistics, inline=True) embed.add_field(name=self._t.transform('modules.stats.list.description'), value=statistics, inline=True) @@ -105,6 +100,7 @@ class StatsGroup(DiscordCommandABC): try: server = self._servers.get_server_by_discord_id(ctx.guild.id) + stats = self._stats.get_statistics_by_server_id(server.server_id) statistic = stats.where(lambda s: s.name == name).single() result = await self._statistic.execute(statistic.code, server) @@ -130,6 +126,8 @@ class StatsGroup(DiscordCommandABC): @view.autocomplete('name') async def view_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]: + server = self._servers.get_server_by_discord_id(interaction.guild.id) + stats = self._stats.get_statistics_by_server_id(server.server_id) return [app_commands.Choice(name=f'{statistic.name}: {statistic.description}', value=statistic.name) for statistic in stats] @stats.command() @@ -144,7 +142,11 @@ class StatsGroup(DiscordCommandABC): self._logger.trace(__name__, f'Finished command stats add') return - form = AddStatisticForm(stats, name, self._message_service, self._logger, self._t) + if ctx.guild is None: + return + + server = self._servers.get_server_by_discord_id(ctx.guild.id) + form = AddStatisticForm(server, self._stats, self._db, name, self._message_service, self._logger, self._t) self._logger.trace(__name__, f'Finished stats add command') self._logger.trace(__name__, f'Started stats command form') await ctx.interaction.response.send_modal(form) @@ -162,8 +164,10 @@ class StatsGroup(DiscordCommandABC): return try: + server = self._servers.get_server_by_discord_id(ctx.guild.id) + stats = self._stats.get_statistics_by_server_id(server.server_id) statistic = stats.where(lambda s: s.name == name).single() - form = AddStatisticForm(stats, name, self._message_service, self._logger, self._t, code=statistic.code, description=statistic.description) + form = AddStatisticForm(server, self._stats, self._db, name, self._message_service, self._logger, self._t, code=statistic.code, description=statistic.description) self._logger.trace(__name__, f'Finished stats edit command') self._logger.trace(__name__, f'Started stats command form') await ctx.interaction.response.send_modal(form) @@ -173,6 +177,8 @@ class StatsGroup(DiscordCommandABC): @edit.autocomplete('name') async def edit_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]: + server = self._servers.get_server_by_discord_id(interaction.guild.id) + stats = self._stats.get_statistics_by_server_id(server.server_id) return [app_commands.Choice(name=f'{statistic.name}: {statistic.description}', value=statistic.name) for statistic in stats] @stats.command() @@ -188,12 +194,18 @@ class StatsGroup(DiscordCommandABC): return try: - stats.remove(stats.where(lambda s: s.name == name).single()) + server = self._servers.get_server_by_discord_id(ctx.guild.id) + statistic = self._stats.get_statistic_by_name(name, server.server_id) + self._stats.delete_statistic(statistic) + self._db.save_changes() + await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.stats.remove.success')) self._logger.trace(__name__, f'Finished stats remove command') except Exception as e: self._logger.error(__name__, f'Cannot remove statistic {name}', e) - await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.stats.edit.failed')) + await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.stats.remove.failed')) @remove.autocomplete('name') async def edit_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]: + server = self._servers.get_server_by_discord_id(interaction.guild.id) + stats = self._stats.get_statistics_by_server_id(server.server_id) return [app_commands.Choice(name=f'{statistic.name}: {statistic.description}', value=statistic.name) for statistic in stats] diff --git a/kdb-bot/src/modules/stats/ui/add_statistic_form.py b/kdb-bot/src/modules/stats/ui/add_statistic_form.py index 073fc9d4..625bac82 100644 --- a/kdb-bot/src/modules/stats/ui/add_statistic_form.py +++ b/kdb-bot/src/modules/stats/ui/add_statistic_form.py @@ -1,11 +1,14 @@ import discord +from cpl_core.database.context import DatabaseContextABC from cpl_query.extension import List from cpl_translation import TranslatePipe from discord import ui, TextStyle from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.logging.command_logger import CommandLogger -from modules.stats.model.statisticmodel import StatisticModel +from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC +from bot_data.model.server import Server +from bot_data.model.statistic import Statistic class AddStatisticForm(ui.Modal): @@ -15,7 +18,9 @@ class AddStatisticForm(ui.Modal): def __init__( self, - stats: List[StatisticModel], + server: Server, + stats: StatisticRepositoryABC, + db: DatabaseContextABC, name: str, message_service: MessageServiceABC, logger: CommandLogger, @@ -25,7 +30,9 @@ class AddStatisticForm(ui.Modal): ): ui.Modal.__init__(self, title=name) + self._server = server self._stats = stats + self._db = db self._name = name self._message_service = message_service self._logger = logger @@ -38,15 +45,26 @@ class AddStatisticForm(ui.Modal): self.description.default = description async def on_submit(self, interaction: discord.Interaction): - statistic = self._stats.where(lambda s: s.name == self._name).single_or_default() + statistic = self._stats.get_statistics_by_server_id(self._server.server_id).where(lambda s: s.name == self._name).single_or_default() + + if interaction.guild is None: + if statistic is None: + await self._message_service.send_interaction_msg(interaction, self._t.transform('modules.stats.add.failed')) + else: + await self._message_service.send_interaction_msg(interaction, self._t.transform('modules.stats.edit.failed')) + return + try: if statistic is None: - self._stats.append(StatisticModel(self._name, self.description.value, self.code.value)) + self._stats.add_statistic(Statistic(self._name, self.description.value, self.code.value, self._server)) + self._db.save_changes() await self._message_service.send_interaction_msg(interaction, self._t.transform('modules.stats.add.success')) return statistic.description = self.description.value statistic.code = self.code.value + self._stats.update_statistic(statistic) + self._db.save_changes() await self._message_service.send_interaction_msg(interaction, self._t.transform('modules.stats.edit.success')) except Exception as e: self._logger.error(__name__, f'Save statistic {self._name} failed', e)