forked from sh-edraft.de/sh_discord_bot
		
	Reviewed-on: sh-edraft.de/kd_discord_bot#102 Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com> Closes #46
This commit is contained in:
		| @@ -3,6 +3,7 @@ | ||||
|     "DefaultProject": "bot", | ||||
|     "Projects": { | ||||
|       "bot": "src/bot/bot.json", | ||||
|       "bot-api": "src/bot_api/bot-api.json", | ||||
|       "bot-core": "src/bot_core/bot-core.json", | ||||
|       "bot-data": "src/bot_data/bot-data.json", | ||||
|       "auto-role": "src/modules/auto_role/auto-role.json", | ||||
| @@ -11,7 +12,7 @@ | ||||
|       "database": "src/modules/database/database.json", | ||||
|       "level": "src/modules/level/level.json", | ||||
|       "permission": "src/modules/permission/permission.json", | ||||
|       "bot-api": "src/bot_api/bot-api.json", | ||||
|       "stats": "src/modules/stats/stats.json", | ||||
|       "get-version": "tools/get_version/get-version.json", | ||||
|       "post-build": "tools/post_build/post-build.json", | ||||
|       "set-version": "tools/set_version/set-version.json" | ||||
|   | ||||
| @@ -10,6 +10,7 @@ from modules.boot_log.boot_log_module import BootLogModule | ||||
| from modules.database.database_module import DatabaseModule | ||||
| from modules.level.level_module import LevelModule | ||||
| from modules.permission.permission_module import PermissionModule | ||||
| from modules.stats.stats_module import StatsModule | ||||
|  | ||||
|  | ||||
| class ModuleList: | ||||
| @@ -26,6 +27,7 @@ class ModuleList: | ||||
|             LevelModule, | ||||
|             PermissionModule, | ||||
|             ApiModule, | ||||
|             StatsModule, | ||||
|             # has to be last! | ||||
|             BootLogModule, | ||||
|             CoreExtensionModule, | ||||
|   | ||||
| @@ -8,6 +8,7 @@ from bot_data.migration.api_migration import ApiMigration | ||||
| from bot_data.migration.auto_role_migration import AutoRoleMigration | ||||
| from bot_data.migration.initial_migration import InitialMigration | ||||
| from bot_data.migration.level_migration import LevelMigration | ||||
| from bot_data.migration.stats_migration import StatsMigration | ||||
| from bot_data.service.migration_service import MigrationService | ||||
|  | ||||
|  | ||||
| @@ -25,3 +26,4 @@ class StartupMigrationExtension(StartupExtensionABC): | ||||
|         services.add_transient(MigrationABC, AutoRoleMigration)  # 03.10.2022 #54 - 0.2.2 | ||||
|         services.add_transient(MigrationABC, ApiMigration)  # 15.10.2022 #70 - 0.3.0 | ||||
|         services.add_transient(MigrationABC, LevelMigration)  # 06.11.2022 #25 - 0.3.0 | ||||
|         services.add_transient(MigrationABC, StatsMigration)  # 09.11.2022 #46 - 0.3.0 | ||||
|   | ||||
| @@ -217,7 +217,30 @@ | ||||
|       } | ||||
|     }, | ||||
|     "database": {}, | ||||
|     "permission": { | ||||
|     "permission": {}, | ||||
|     "stats": { | ||||
|       "list": { | ||||
|         "statistic": "Statistik", | ||||
|         "description": "Beschreibung", | ||||
|         "nothing_found": "Keine Statistiken gefunden." | ||||
|       }, | ||||
|       "view": { | ||||
|         "statistic": "Statistik", | ||||
|         "description": "Beschreibung", | ||||
|         "failed": "Statistik kann nicht gezeigt werden :(" | ||||
|       }, | ||||
|       "add": { | ||||
|         "failed": "Statistik kann nicht hinzugefügt werden :(", | ||||
|         "success": "Statistik wurde hinzugefügt :D" | ||||
|       }, | ||||
|       "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" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "api": { | ||||
|   | ||||
| @@ -11,7 +11,7 @@ Discord bot  for the Keksdose discord Server | ||||
|  | ||||
| """ | ||||
|  | ||||
| __title__ = 'bot_api.abc' | ||||
| __title__ = 'bot_api.service' | ||||
| __author__ = 'Sven Heidemann' | ||||
| __license__ = 'MIT' | ||||
| __copyright__ = 'Copyright (c) 2022 sh-edraft.de' | ||||
|   | ||||
| @@ -11,7 +11,7 @@ Discord bot  for the Keksdose discord Server | ||||
|  | ||||
| """ | ||||
|  | ||||
| __title__ = 'bot_core.abc' | ||||
| __title__ = 'bot_core.service' | ||||
| __author__ = 'Sven Heidemann' | ||||
| __license__ = 'MIT' | ||||
| __copyright__ = 'Copyright (c) 2022 sh-edraft.de' | ||||
|   | ||||
| @@ -3,6 +3,7 @@ from typing import Union | ||||
|  | ||||
| import discord | ||||
| from cpl_query.extension import List | ||||
| from discord import Interaction | ||||
| from discord.ext.commands import Context | ||||
|  | ||||
|  | ||||
| @@ -10,18 +11,21 @@ class MessageServiceABC(ABC): | ||||
|  | ||||
|     @abstractmethod | ||||
|     def __init__(self): pass | ||||
|      | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False): pass | ||||
|      | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def delete_message(self, message: discord.Message, without_tracking=False): pass | ||||
|      | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed], without_tracking=True): pass | ||||
|      | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member], without_tracking=False): pass | ||||
|      | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, wait_before_delete: int = None, without_tracking=True): pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def send_interaction_msg(self, interaction: Interaction, message: Union[str, discord.Embed], is_persistent: bool = False, wait_before_delete: int = None, without_tracking=True): pass | ||||
|   | ||||
| @@ -2,7 +2,6 @@ from enum import Enum | ||||
|  | ||||
|  | ||||
| class FeatureFlagsEnum(Enum): | ||||
|  | ||||
|     # modules | ||||
|     api_module = 'ApiModule' | ||||
|     admin_module = 'AdminModule' | ||||
| @@ -16,6 +15,7 @@ class FeatureFlagsEnum(Enum): | ||||
|     level_module = 'LevelModule' | ||||
|     moderator_module = 'ModeratorModule' | ||||
|     permission_module = 'PermissionModule' | ||||
|     stats_module = 'StatsModule' | ||||
|     # features | ||||
|     api_only = 'ApiOnly' | ||||
|     presence = 'Presence' | ||||
|   | ||||
| @@ -25,6 +25,7 @@ class FeatureFlagsSettings(ConfigurationModelABC): | ||||
|             FeatureFlagsEnum.database_module.value: True,  # 02.10.2022 #48 | ||||
|             FeatureFlagsEnum.moderator_module.value: False,  # 02.10.2022 #48 | ||||
|             FeatureFlagsEnum.permission_module.value: True,  # 02.10.2022 #48 | ||||
|             FeatureFlagsEnum.stats_module.value: True,  # 08.11.2022 #46 | ||||
|             # features | ||||
|             FeatureFlagsEnum.api_only.value: False,  # 13.10.2022 #70 | ||||
|             FeatureFlagsEnum.presence.value: True,  # 03.10.2022 #56 | ||||
|   | ||||
| @@ -6,6 +6,7 @@ from cpl_core.configuration.configuration_abc import ConfigurationABC | ||||
| from cpl_core.database.context.database_context_abc import DatabaseContextABC | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
| from cpl_query.extension import List | ||||
| from discord import Interaction | ||||
| from discord.ext.commands import Context | ||||
|  | ||||
| from bot_core.abc.message_service_abc import MessageServiceABC | ||||
| @@ -117,3 +118,31 @@ class MessageService(MessageServiceABC): | ||||
|  | ||||
|             if ctx.guild is not None: | ||||
|                 await self.delete_message(msg, without_tracking) | ||||
|  | ||||
|     async def send_interaction_msg(self, interaction: Interaction, message: Union[str, discord.Embed], is_persistent: bool = False, wait_before_delete: int = None, without_tracking=False): | ||||
|         if interaction is None: | ||||
|             self._logger.warn(__name__, 'Message context is empty') | ||||
|             self._logger.debug(__name__, f'Message: {message}') | ||||
|             return | ||||
|  | ||||
|         self._logger.debug(__name__, f'Try to send message\t\t{message}\n\tto: {interaction.channel}') | ||||
|         try: | ||||
|             if isinstance(message, discord.Embed): | ||||
|                 await interaction.response.send_message(embed=message) | ||||
|             else: | ||||
|                 await interaction.response.send_message(message) | ||||
|         except Exception as e: | ||||
|             self._logger.error(__name__, f'Send message to channel {interaction.channel.id} failed', e) | ||||
|         else: | ||||
|             self._logger.info(__name__, f'Sent message to channel {interaction.channel.id}') | ||||
|             if not without_tracking and interaction.guild is not None: | ||||
|                 self._clients.append_sent_message_count(self._bot.user.id, interaction.guild.id, 1) | ||||
|                 self._db.save_changes() | ||||
|  | ||||
|             if wait_before_delete is not None: | ||||
|                 await asyncio.sleep(wait_before_delete) | ||||
|  | ||||
|             if is_persistent: | ||||
|                 return | ||||
|  | ||||
|             await self.delete_message(await interaction.original_response(), without_tracking) | ||||
|   | ||||
| @@ -11,7 +11,7 @@ Discord bot  for the Keksdose discord Server | ||||
|  | ||||
| """ | ||||
|  | ||||
| __title__ = 'bot_data.abc' | ||||
| __title__ = 'bot_data.service' | ||||
| __author__ = 'Sven Heidemann' | ||||
| __license__ = 'MIT' | ||||
| __copyright__ = 'Copyright (c) 2022 sh-edraft.de' | ||||
|   | ||||
							
								
								
									
										36
									
								
								kdb-bot/src/bot_data/abc/statistic_repository_abc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								kdb-bot/src/bot_data/abc/statistic_repository_abc.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| from abc import ABC, abstractmethod | ||||
| from typing import Optional | ||||
|  | ||||
| from cpl_query.extension import List | ||||
|  | ||||
| from bot_data.model.statistic import Statistic | ||||
|  | ||||
|  | ||||
| class StatisticRepositoryABC(ABC): | ||||
|  | ||||
|     @abstractmethod | ||||
|     def __init__(self): pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_statistics(self) -> List[Statistic]: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_statistics_by_server_id(self, server_id: int) -> List[Statistic]: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_statistic_by_id(self, id: int) -> Statistic: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_statistic_by_name(self, name: str, server_id: int) -> Statistic: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def find_statistic_by_name(self, name: str, server_id: int) -> Optional[Statistic]: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def add_statistic(self, statistic: Statistic): pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def update_statistic(self, statistic: Statistic): pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def delete_statistic(self, statistic: Statistic): pass | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										36
									
								
								kdb-bot/src/bot_data/migration/stats_migration.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								kdb-bot/src/bot_data/migration/stats_migration.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| from bot_core.logging.database_logger import DatabaseLogger | ||||
| from bot_data.abc.migration_abc import MigrationABC | ||||
| from bot_data.db_context import DBContext | ||||
|  | ||||
|  | ||||
| class StatsMigration(MigrationABC): | ||||
|     name = '0.3_StatsMigration' | ||||
|  | ||||
|     def __init__(self, logger: DatabaseLogger, db: DBContext): | ||||
|         MigrationABC.__init__(self) | ||||
|         self._logger = logger | ||||
|         self._db = db | ||||
|         self._cursor = db.cursor | ||||
|  | ||||
|     def upgrade(self): | ||||
|         self._logger.debug(__name__, 'Running upgrade') | ||||
|  | ||||
|         self._cursor.execute( | ||||
|             str(f""" | ||||
|             CREATE TABLE IF NOT EXISTS `Statistics` ( | ||||
|                 `Id` BIGINT NOT NULL AUTO_INCREMENT, | ||||
|                 `Name` VARCHAR(255) NOT NULL, | ||||
|                 `Description` VARCHAR(255) NOT NULL, | ||||
|                 `Code` LONGTEXT NOT NULL, | ||||
|                 `ServerId` BIGINT, | ||||
|                 `CreatedAt` DATETIME(6), | ||||
|                 `LastModifiedAt` DATETIME(6), | ||||
|                 PRIMARY KEY(`Id`), | ||||
|                 FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`) | ||||
|             ); | ||||
|             """) | ||||
|         ) | ||||
|  | ||||
|     def downgrade(self): | ||||
|         self._cursor.execute('DROP TABLE `Statistics`;') | ||||
|  | ||||
							
								
								
									
										109
									
								
								kdb-bot/src/bot_data/model/statistic.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								kdb-bot/src/bot_data/model/statistic.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| from datetime import datetime | ||||
|  | ||||
| from cpl_core.database import TableABC | ||||
| from cpl_core.utils import CredentialManager | ||||
|  | ||||
| from bot_data.model.server import Server | ||||
|  | ||||
|  | ||||
| class Statistic(TableABC): | ||||
|  | ||||
|     def __init__(self, name: str, description: str, code: str, server: Server, created_at: datetime=None, modified_at: datetime=None, id=0): | ||||
|         self._id = id | ||||
|         self._name = name | ||||
|         self._description = description | ||||
|         self._code = CredentialManager.encrypt(code) | ||||
|         self._server = server | ||||
|  | ||||
|         TableABC.__init__(self) | ||||
|         self._created_at = created_at if created_at is not None else self._created_at | ||||
|         self._modified_at = modified_at if modified_at is not None else self._modified_at | ||||
|      | ||||
|     @property | ||||
|     def id(self) -> int: | ||||
|         return self._id | ||||
|      | ||||
|     @property | ||||
|     def name(self) -> str: | ||||
|         return self._name | ||||
|      | ||||
|     @property | ||||
|     def description(self) -> str: | ||||
|         return self._description | ||||
|      | ||||
|     @description.setter | ||||
|     def description(self, value: str): | ||||
|         self._description = value | ||||
|          | ||||
|     @property | ||||
|     def code(self) -> str: | ||||
|         return CredentialManager.decrypt(self._code) | ||||
|      | ||||
|     @code.setter | ||||
|     def code(self, value: str): | ||||
|         self._code = CredentialManager.encrypt(value) | ||||
|          | ||||
|     @property | ||||
|     def server(self) -> Server: | ||||
|         return self._server | ||||
|          | ||||
|     @staticmethod | ||||
|     def get_select_all_string() -> str: | ||||
|         return str(f""" | ||||
|             SELECT * FROM `Statistics`; | ||||
|         """) | ||||
|          | ||||
|     @staticmethod | ||||
|     def get_select_by_id_string(id: int) -> str: | ||||
|         return str(f""" | ||||
|             SELECT * FROM `Statistics` | ||||
|             WHERE `Id` = {id}; | ||||
|         """) | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_select_by_name_string(name: str, s_id: int) -> str: | ||||
|         return str(f""" | ||||
|             SELECT * FROM `Statistics` | ||||
|             WHERE `ServerId` = {s_id} | ||||
|             AND `Name` = '{name}'; | ||||
|         """) | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_select_by_server_string(s_id: int) -> str: | ||||
|         return str(f""" | ||||
|             SELECT * FROM `Statistics` | ||||
|             WHERE `ServerId` = {s_id}; | ||||
|         """) | ||||
|  | ||||
|     @property | ||||
|     def insert_string(self) -> str: | ||||
|         return str(f""" | ||||
|             INSERT INTO `Statistics` ( | ||||
|                 `Name`, `Description`, `Code`, `ServerId`, `CreatedAt`, `LastModifiedAt` | ||||
|             ) VALUES ( | ||||
|                 '{self._name}', | ||||
|                 '{self._description}', | ||||
|                 '{self._code}', | ||||
|                 {self._server.server_id}, | ||||
|                 '{self._created_at}', | ||||
|                 '{self._modified_at}' | ||||
|             ); | ||||
|         """) | ||||
|  | ||||
|     @property | ||||
|     def udpate_string(self) -> str: | ||||
|         return str(f""" | ||||
|             UPDATE `Statistics` | ||||
|             SET `Name` = '{self._name}', | ||||
|             `Description` = '{self._description}', | ||||
|             `Code` = '{self._code}', | ||||
|             `LastModifiedAt` = '{self._modified_at}' | ||||
|             WHERE `Id` = {self._id}; | ||||
|         """) | ||||
|  | ||||
|     @property | ||||
|     def delete_string(self) -> str: | ||||
|         return str(f""" | ||||
|             DELETE FROM `Statistics` | ||||
|             WHERE `Id` = {self._id}; | ||||
|         """) | ||||
							
								
								
									
										93
									
								
								kdb-bot/src/bot_data/service/statistic_repository_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								kdb-bot/src/bot_data/service/statistic_repository_service.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| 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 | ||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC | ||||
| from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC | ||||
| from bot_data.model.statistic import Statistic | ||||
|  | ||||
|  | ||||
| class StatisticRepositoryService(StatisticRepositoryABC): | ||||
|  | ||||
|     def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC, statistics: ServerRepositoryABC): | ||||
|         self._logger = logger | ||||
|         self._context = db_context | ||||
|  | ||||
|         self._statistics = statistics | ||||
|  | ||||
|         StatisticRepositoryABC.__init__(self) | ||||
|  | ||||
|     @staticmethod | ||||
|     def _get_value_from_result(value: any) -> Optional[any]: | ||||
|         if isinstance(value, str) and 'NULL' in value: | ||||
|             return None | ||||
|  | ||||
|         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]), | ||||
|             code, | ||||
|             self._statistics.get_server_by_id(sql_result[4]), | ||||
|             id=self._get_value_from_result(sql_result[0]) | ||||
|         ) | ||||
|  | ||||
|         return statistic | ||||
|  | ||||
|     def get_statistics(self) -> List[Statistic]: | ||||
|         statistics = List(Statistic) | ||||
|         self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_all_string()}') | ||||
|         results = self._context.select(Statistic.get_select_all_string()) | ||||
|         for result in results: | ||||
|             statistics.append(self._statistic_from_result(result)) | ||||
|  | ||||
|         return statistics | ||||
|  | ||||
|     def get_statistics_by_server_id(self, server_id: int) -> List[Statistic]: | ||||
|         statistics = List(Statistic) | ||||
|         self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_server_string(server_id)}') | ||||
|         results = self._context.select(Statistic.get_select_by_server_string(server_id)) | ||||
|         for result in results: | ||||
|             statistics.append(self._statistic_from_result(result)) | ||||
|  | ||||
|         return statistics | ||||
|  | ||||
|     def get_statistic_by_id(self, id: int) -> Statistic: | ||||
|         self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_id_string(id)}') | ||||
|         result = self._context.select(Statistic.get_select_by_id_string(id))[0] | ||||
|         return self._statistic_from_result(result) | ||||
|  | ||||
|     def get_statistic_by_name(self, name: str, server_id: int) -> Statistic: | ||||
|         self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_name_string(name, server_id)}') | ||||
|         result = self._context.select(Statistic.get_select_by_name_string(name, server_id))[0] | ||||
|         return self._statistic_from_result(result) | ||||
|  | ||||
|     def find_statistic_by_name(self, name: str, server_id: int) -> Optional[Statistic]: | ||||
|         self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_name_string(name, server_id)}') | ||||
|         result = self._context.select(Statistic.get_select_by_name_string(name, server_id)) | ||||
|         if result is None or len(result) == 0: | ||||
|             return None | ||||
|  | ||||
|         result = result[0] | ||||
|  | ||||
|         return self._statistic_from_result(result) | ||||
|  | ||||
|     def add_statistic(self, statistic: Statistic): | ||||
|         self._logger.trace(__name__, f'Send SQL command: {statistic.insert_string}') | ||||
|         self._context.cursor.execute(statistic.insert_string) | ||||
|  | ||||
|     def update_statistic(self, statistic: Statistic): | ||||
|         self._logger.trace(__name__, f'Send SQL command: {statistic.udpate_string}') | ||||
|         self._context.cursor.execute(statistic.udpate_string) | ||||
|  | ||||
|     def delete_statistic(self, statistic: Statistic): | ||||
|         self._logger.trace(__name__, f'Send SQL command: {statistic.delete_string}') | ||||
|         self._context.cursor.execute(statistic.delete_string) | ||||
| @@ -11,7 +11,7 @@ Discord bot  for the Keksdose discord Server | ||||
|  | ||||
| """ | ||||
|  | ||||
| __title__ = 'modules.base.abc' | ||||
| __title__ = 'modules.base.service' | ||||
| __author__ = 'Sven Heidemann' | ||||
| __license__ = 'MIT' | ||||
| __copyright__ = 'Copyright (c) 2022 sh-edraft.de' | ||||
|   | ||||
| @@ -11,7 +11,7 @@ Discord bot  for the Keksdose discord Server | ||||
|  | ||||
| """ | ||||
|  | ||||
| __title__ = 'modules.permission.abc' | ||||
| __title__ = 'modules.permission.service' | ||||
| __author__ = 'Sven Heidemann' | ||||
| __license__ = 'MIT' | ||||
| __copyright__ = 'Copyright (c) 2022 sh-edraft.de' | ||||
|   | ||||
							
								
								
									
										1
									
								
								kdb-bot/src/modules/stats/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								kdb-bot/src/modules/stats/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| # imports:  | ||||
							
								
								
									
										1
									
								
								kdb-bot/src/modules/stats/command/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								kdb-bot/src/modules/stats/command/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| # imports | ||||
							
								
								
									
										216
									
								
								kdb-bot/src/modules/stats/command/stats_group.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								kdb-bot/src/modules/stats/command/stats_group.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| from typing import List as TList | ||||
|  | ||||
| import discord | ||||
| from cpl_core.database.context import DatabaseContextABC | ||||
| from cpl_discord.command import DiscordCommandABC | ||||
| from cpl_translation import TranslatePipe | ||||
| from discord import app_commands | ||||
| from discord.ext import commands | ||||
| from discord.ext.commands import Context | ||||
|  | ||||
| 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.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 | ||||
|  | ||||
|  | ||||
| class StatsGroup(DiscordCommandABC): | ||||
|  | ||||
|     def __init__( | ||||
|             self, | ||||
|             logger: CommandLogger, | ||||
|             message_service: MessageServiceABC, | ||||
|             client_utils: ClientUtilsServiceABC, | ||||
|             translate: TranslatePipe, | ||||
|             permission_service: PermissionServiceABC, | ||||
|             statistic: StatisticService, | ||||
|             servers: ServerRepositoryABC, | ||||
|             stats: StatisticRepositoryABC, | ||||
|             db: DatabaseContextABC, | ||||
|     ): | ||||
|         DiscordCommandABC.__init__(self) | ||||
|  | ||||
|         self._logger = logger | ||||
|         self._client_utils = client_utils | ||||
|         self._message_service = message_service | ||||
|         self._t = translate | ||||
|         self._permissions = permission_service | ||||
|         self._statistic = statistic | ||||
|         self._servers = servers | ||||
|         self._stats = stats | ||||
|         self._db = db | ||||
|  | ||||
|     @commands.hybrid_group() | ||||
|     @commands.guild_only() | ||||
|     async def stats(self, ctx: Context): | ||||
|         pass | ||||
|  | ||||
|     @stats.command() | ||||
|     @commands.guild_only() | ||||
|     async def list(self, ctx: Context, wait: int = None): | ||||
|         self._logger.debug(__name__, f'Received command stats list {ctx}') | ||||
|         if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx): | ||||
|             return | ||||
|  | ||||
|         if not self._permissions.is_member_moderator(ctx.author): | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('common.no_permission_message')) | ||||
|             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}' | ||||
|  | ||||
|         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=descriptions, inline=True) | ||||
|         await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait) | ||||
|         self._logger.trace(__name__, f'Finished command stats list') | ||||
|  | ||||
|     @stats.command() | ||||
|     @commands.guild_only() | ||||
|     async def view(self, ctx: Context, name: str, wait: int = None): | ||||
|         self._logger.debug(__name__, f'Received command stats view {ctx}:{name}') | ||||
|         if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx): | ||||
|             return | ||||
|  | ||||
|         if not self._permissions.is_member_moderator(ctx.author): | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('common.no_permission_message')) | ||||
|             self._logger.trace(__name__, f'Finished command stats view') | ||||
|             return | ||||
|  | ||||
|         if ctx.guild is None: | ||||
|             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() | ||||
|             result = await self._statistic.execute(statistic.code, server) | ||||
|  | ||||
|             embed = discord.Embed( | ||||
|                 title=statistic.name, | ||||
|                 description=statistic.description, | ||||
|                 color=int('ef9d0d', 16) | ||||
|             ) | ||||
|  | ||||
|             for i in range(result.header.count()): | ||||
|                 header = result.header[i] | ||||
|                 value = '' | ||||
|                 for row in result.values: | ||||
|                     value += f'\n{row[i]}' | ||||
|                 embed.add_field(name=header, value=value, inline=True) | ||||
|  | ||||
|             await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait) | ||||
|         except Exception as e: | ||||
|             self._logger.error(__name__, f'Cannot view statistic {name}', e) | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.stats.view.failed')) | ||||
|  | ||||
|         self._logger.trace(__name__, f'Finished stats view command') | ||||
|  | ||||
|     @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() | ||||
|     @commands.guild_only() | ||||
|     async def add(self, ctx: Context, name: str): | ||||
|         self._logger.debug(__name__, f'Received command stats add {ctx}: {name}') | ||||
|         if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx): | ||||
|             return | ||||
|  | ||||
|         if not self._permissions.is_member_technician(ctx.author): | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('common.no_permission_message')) | ||||
|             self._logger.trace(__name__, f'Finished command stats add') | ||||
|             return | ||||
|  | ||||
|         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) | ||||
|  | ||||
|     @stats.command() | ||||
|     @commands.guild_only() | ||||
|     async def edit(self, ctx: Context, name: str): | ||||
|         self._logger.debug(__name__, f'Received command stats edit {ctx}: {name}') | ||||
|         if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx): | ||||
|             return | ||||
|  | ||||
|         if not self._permissions.is_member_technician(ctx.author): | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('common.no_permission_message')) | ||||
|             self._logger.trace(__name__, f'Finished command stats edit') | ||||
|             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(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) | ||||
|         except Exception as e: | ||||
|             self._logger.error(__name__, f'Cannot edit statistic {name}', e) | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.stats.edit.failed')) | ||||
|  | ||||
|     @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() | ||||
|     @commands.guild_only() | ||||
|     async def remove(self, ctx: Context, name: str): | ||||
|         self._logger.debug(__name__, f'Received command stats remove {ctx}: {name}') | ||||
|         if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx): | ||||
|             return | ||||
|  | ||||
|         if not self._permissions.is_member_technician(ctx.author): | ||||
|             await self._message_service.send_ctx_msg(ctx, self._t.transform('common.no_permission_message')) | ||||
|             self._logger.trace(__name__, f'Finished command stats remove') | ||||
|             return | ||||
|  | ||||
|         try: | ||||
|             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.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] | ||||
							
								
								
									
										1
									
								
								kdb-bot/src/modules/stats/model/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								kdb-bot/src/modules/stats/model/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| # imports | ||||
							
								
								
									
										24
									
								
								kdb-bot/src/modules/stats/model/statistic_result.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								kdb-bot/src/modules/stats/model/statistic_result.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| from cpl_query.extension import List | ||||
|  | ||||
|  | ||||
| class StatisticResult: | ||||
|  | ||||
|     def __init__(self): | ||||
|         self._header = List(str) | ||||
|         self._values = List(List) | ||||
|  | ||||
|     @property | ||||
|     def header(self) -> List[str]: | ||||
|         return self._header | ||||
|  | ||||
|     @header.setter | ||||
|     def header(self, value: List[str]): | ||||
|         self._header = value | ||||
|  | ||||
|     @property | ||||
|     def values(self) -> List[List]: | ||||
|         return self._values | ||||
|  | ||||
|     @values.setter | ||||
|     def values(self, value: List[List]): | ||||
|         self._values = value | ||||
							
								
								
									
										1
									
								
								kdb-bot/src/modules/stats/service/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								kdb-bot/src/modules/stats/service/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| # imports | ||||
							
								
								
									
										96
									
								
								kdb-bot/src/modules/stats/service/statistic_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								kdb-bot/src/modules/stats/service/statistic_service.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| from abc import abstractmethod | ||||
|  | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
| from cpl_query.extension import List | ||||
| from discord import Guild | ||||
|  | ||||
| from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC | ||||
| 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.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 bot_data.model.auto_role import AutoRole | ||||
| from bot_data.model.client import Client | ||||
| from bot_data.model.known_user import KnownUser | ||||
| from bot_data.model.level import Level | ||||
| from bot_data.model.server import Server | ||||
| from bot_data.model.user import User | ||||
| from bot_data.model.user_joined_server import UserJoinedServer | ||||
| from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel | ||||
| from modules.stats.model.statistic_result import StatisticResult | ||||
|  | ||||
|  | ||||
| class StatisticService: | ||||
|  | ||||
|     def __init__( | ||||
|             self, | ||||
|             auto_roles: AutoRoleRepositoryABC, | ||||
|             clients: ClientRepositoryABC, | ||||
|             known_users: KnownUserRepositoryABC, | ||||
|             levels: LevelRepositoryABC, | ||||
|             servers: ServerRepositoryABC, | ||||
|             user_joined_servers: UserJoinedServerRepositoryABC, | ||||
|             user_joined_voice_channel: UserJoinedVoiceChannelRepositoryABC, | ||||
|             users: UserRepositoryABC, | ||||
|             bot: DiscordBotServiceABC, | ||||
|     ): | ||||
|         self._auto_roles = auto_roles | ||||
|         self._clients = clients | ||||
|         self._known_users = known_users | ||||
|         self._levels = levels | ||||
|         self._servers = servers | ||||
|         self._user_joined_servers = user_joined_servers | ||||
|         self._user_joined_voice_channel = user_joined_voice_channel | ||||
|         self._users = users | ||||
|         self._bot = bot | ||||
|  | ||||
|     async def execute(self, code: str, server: Server) -> StatisticResult: | ||||
|         guild = self._bot.guilds.where(lambda g: g.id == server.discord_server_id).single() | ||||
|  | ||||
|         return await self.get_data( | ||||
|             code, | ||||
|             self._auto_roles | ||||
|                 .get_auto_roles() | ||||
|                 .where(lambda x: x.server.server_id == server.server_id), | ||||
|             self._clients | ||||
|                 .get_clients() | ||||
|                 .where(lambda x: x.server.server_id == server.server_id), | ||||
|             self._known_users.get_users(), | ||||
|             self._levels | ||||
|                 .get_levels() | ||||
|                 .where(lambda x: x.server.server_id == server.server_id), | ||||
|             self._servers | ||||
|                 .get_servers() | ||||
|                 .where(lambda x: x.server_id == server.server_id), | ||||
|             self._user_joined_servers | ||||
|                 .get_user_joined_servers() | ||||
|                 .where(lambda x: x.user.server.server_id == server.server_id), | ||||
|             self._user_joined_voice_channel | ||||
|                 .get_user_joined_voice_channels() | ||||
|                 .where(lambda x: x.user.server.server_id == server.server_id), | ||||
|             self._users | ||||
|                 .get_users() | ||||
|                 .where(lambda x: x.server.server_id == server.server_id), | ||||
|             guild | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     async def get_data( | ||||
|             code: str, | ||||
|             auto_roles: List[AutoRole], | ||||
|             clients: List[Client], | ||||
|             known_users: List[KnownUser], | ||||
|             levels: List[Level], | ||||
|             servers: List[Server], | ||||
|             user_joined_servers: List[UserJoinedServer], | ||||
|             user_joined_voice_channel: List[UserJoinedVoiceChannel], | ||||
|             users: List[User], | ||||
|             guild: Guild | ||||
|     ) -> StatisticResult: | ||||
|         result = StatisticResult() | ||||
|         exec(code) | ||||
|  | ||||
|         return result | ||||
							
								
								
									
										46
									
								
								kdb-bot/src/modules/stats/stats.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								kdb-bot/src/modules/stats/stats.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| { | ||||
|   "ProjectSettings": { | ||||
|     "Name": "stats", | ||||
|     "Version": { | ||||
|       "Major": "0", | ||||
|       "Minor": "0", | ||||
|       "Micro": "0" | ||||
|     }, | ||||
|     "Author": "", | ||||
|     "AuthorEmail": "", | ||||
|     "Description": "", | ||||
|     "LongDescription": "", | ||||
|     "URL": "", | ||||
|     "CopyrightDate": "", | ||||
|     "CopyrightName": "", | ||||
|     "LicenseName": "", | ||||
|     "LicenseDescription": "", | ||||
|     "Dependencies": [ | ||||
|       "cpl-core>=2022.10.0.post7" | ||||
|     ], | ||||
|     "DevDependencies": [ | ||||
|       "cpl-cli>=2022.10.1" | ||||
|     ], | ||||
|     "PythonVersion": ">=3.10.4", | ||||
|     "PythonPath": { | ||||
|       "linux": "" | ||||
|     }, | ||||
|     "Classifiers": [] | ||||
|   }, | ||||
|   "BuildSettings": { | ||||
|     "ProjectType": "library", | ||||
|     "SourcePath": "", | ||||
|     "OutputPath": "../../dist", | ||||
|     "Main": "stats.main", | ||||
|     "EntryPoint": "stats", | ||||
|     "IncludePackageData": false, | ||||
|     "Included": [], | ||||
|     "Excluded": [ | ||||
|       "*/__pycache__", | ||||
|       "*/logs", | ||||
|       "*/tests" | ||||
|     ], | ||||
|     "PackageData": {}, | ||||
|     "ProjectReferences": [] | ||||
|   } | ||||
| } | ||||
							
								
								
									
										24
									
								
								kdb-bot/src/modules/stats/stats_module.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								kdb-bot/src/modules/stats/stats_module.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| from cpl_core.configuration import ConfigurationABC | ||||
| from cpl_core.dependency_injection import ServiceCollectionABC | ||||
| from cpl_core.environment import ApplicationEnvironmentABC | ||||
| from cpl_discord.service.discord_collection_abc import DiscordCollectionABC | ||||
|  | ||||
| from bot_core.abc.module_abc import ModuleABC | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
| from modules.stats.command.stats_group import StatsGroup | ||||
| from modules.stats.service.statistic_service import StatisticService | ||||
|  | ||||
|  | ||||
| class StatsModule(ModuleABC): | ||||
|  | ||||
|     def __init__(self, dc: DiscordCollectionABC): | ||||
|         ModuleABC.__init__(self, dc, FeatureFlagsEnum.stats_module) | ||||
|  | ||||
|     def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): | ||||
|         pass | ||||
|  | ||||
|     def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): | ||||
|         services.add_transient(StatisticService) | ||||
|         # commands | ||||
|         self._dc.add_command(StatsGroup) | ||||
|         # events | ||||
							
								
								
									
										1
									
								
								kdb-bot/src/modules/stats/ui/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								kdb-bot/src/modules/stats/ui/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| # imports | ||||
							
								
								
									
										76
									
								
								kdb-bot/src/modules/stats/ui/add_statistic_form.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								kdb-bot/src/modules/stats/ui/add_statistic_form.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| 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 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): | ||||
|  | ||||
|     description = ui.TextInput(label='Beschreibung', required=True) | ||||
|     code = ui.TextInput(label='Code', required=True, style=TextStyle.long) | ||||
|  | ||||
|     def __init__( | ||||
|             self, | ||||
|             server: Server, | ||||
|             stats: StatisticRepositoryABC, | ||||
|             db: DatabaseContextABC, | ||||
|             name: str, | ||||
|             message_service: MessageServiceABC, | ||||
|             logger: CommandLogger, | ||||
|             t: TranslatePipe, | ||||
|             code: str = None, | ||||
|             description: str = None, | ||||
|     ): | ||||
|         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 | ||||
|         self._t = t | ||||
|  | ||||
|         if code is not None: | ||||
|             self.code.default = code | ||||
|  | ||||
|         if description is not None: | ||||
|             self.description.default = description | ||||
|  | ||||
|     async def on_submit(self, interaction: discord.Interaction): | ||||
|         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.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) | ||||
|             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')) | ||||
|  | ||||
|         self._logger.trace(__name__, f'Finished stats command form') | ||||
		Reference in New Issue
	
	Block a user