Merge pull request '0.3 - Log Befehl (#44)' (#125) from #44 into 0.3

Reviewed-on: sh-edraft.de/kd_discord_bot#125
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #44
This commit is contained in:
Ebola-Chan 2022-11-17 23:03:33 +01:00
commit 8445c23e7f
15 changed files with 199 additions and 20 deletions

View File

@ -13,6 +13,7 @@
"level": "src/modules/level/level.json", "level": "src/modules/level/level.json",
"permission": "src/modules/permission/permission.json", "permission": "src/modules/permission/permission.json",
"stats": "src/modules/stats/stats.json", "stats": "src/modules/stats/stats.json",
"technician": "src/modules/technician/technician.json",
"get-version": "tools/get_version/get-version.json", "get-version": "tools/get_version/get-version.json",
"post-build": "tools/post_build/post-build.json", "post-build": "tools/post_build/post-build.json",
"set-version": "tools/set_version/set-version.json" "set-version": "tools/set_version/set-version.json"

View File

@ -11,6 +11,7 @@ from modules.database.database_module import DatabaseModule
from modules.level.level_module import LevelModule from modules.level.level_module import LevelModule
from modules.permission.permission_module import PermissionModule from modules.permission.permission_module import PermissionModule
from modules.stats.stats_module import StatsModule from modules.stats.stats_module import StatsModule
from modules.technician.technician_module import TechnicianModule
class ModuleList: class ModuleList:
@ -28,6 +29,7 @@ class ModuleList:
PermissionModule, PermissionModule,
ApiModule, ApiModule,
StatsModule, StatsModule,
TechnicianModule,
# has to be last! # has to be last!
BootLogModule, BootLogModule,
CoreExtensionModule, CoreExtensionModule,

View File

@ -72,11 +72,6 @@
} }
}, },
"modules": { "modules": {
"admin": {
"restart_message": "Bin gleich wieder da :D",
"shutdown_message": "Trauert nicht um mich, es war eine logische Entscheidung. Das Wohl von Vielen, es wiegt schwerer als das Wohl von Wenigen oder eines Einzelnen. Ich war es und ich werde es immer sein, Euer Freund. Lebt lange und in Frieden :)",
"deploy_message": "Der neue Stand wurde hochgeladen."
},
"auto_role": { "auto_role": {
"list": { "list": {
"title": "Beobachtete Nachrichten:", "title": "Beobachtete Nachrichten:",
@ -249,6 +244,11 @@
"failed": "Statistik kann nicht gelöscht werden :(", "failed": "Statistik kann nicht gelöscht werden :(",
"success": "Statistik wurde gelöscht :D" "success": "Statistik wurde gelöscht :D"
} }
},
"technician": {
"restart_message": "Bin gleich wieder da :D",
"shutdown_message": "Trauert nicht um mich, es war eine logische Entscheidung. Das Wohl von Vielen, es wiegt schwerer als das Wohl von Wenigen oder eines Einzelnen. Ich war es und ich werde es immer sein, Euer Freund. Lebt lange und in Frieden :)",
"log_message": "Hier sind deine Logdateien! :)"
} }
}, },
"api": { "api": {

@ -1 +1 @@
Subproject commit 98303ffd45445eecfad57f8b1be86729de3661d2 Subproject commit 43a44b31f2efc644baadbf830b6414bab085fdea

View File

@ -13,10 +13,14 @@ class CustomFileLoggerABC(Logger, ABC):
@abstractmethod @abstractmethod
def __init__(self, key: str, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC): def __init__(self, key: str, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC):
self._key = key self._key = key
settings: LoggingSettings = config.get_configuration(f'{FileLoggingSettings.__name__}_{key}') self._settings: LoggingSettings = config.get_configuration(f'{FileLoggingSettings.__name__}_{key}')
Logger.__init__(self, settings, time_format, env) Logger.__init__(self, self._settings, time_format, env)
self._begin_log() self._begin_log()
@property
def settings(self) -> LoggingSettings:
return self._settings
def _begin_log(self): def _begin_log(self):
console_level = self._console.value console_level = self._console.value
self._console = LoggingLevelEnum.OFF self._console = LoggingLevelEnum.OFF

View File

@ -28,4 +28,4 @@ class MessageServiceABC(ABC):
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 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 @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 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, **kwargs): pass

View File

@ -119,7 +119,7 @@ class MessageService(MessageServiceABC):
if ctx.guild is not None: if ctx.guild is not None:
await self.delete_message(msg, without_tracking) 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): 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, **kwargs):
if interaction is None: if interaction is None:
self._logger.warn(__name__, 'Message context is empty') self._logger.warn(__name__, 'Message context is empty')
self._logger.debug(__name__, f'Message: {message}') self._logger.debug(__name__, f'Message: {message}')
@ -128,9 +128,9 @@ class MessageService(MessageServiceABC):
self._logger.debug(__name__, f'Try to send message\t\t{message}\n\tto: {interaction.channel}') self._logger.debug(__name__, f'Try to send message\t\t{message}\n\tto: {interaction.channel}')
try: try:
if isinstance(message, discord.Embed): if isinstance(message, discord.Embed):
await interaction.response.send_message(embed=message) await interaction.response.send_message(embed=message, **kwargs)
else: else:
await interaction.response.send_message(message) await interaction.response.send_message(message, **kwargs)
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Send message to channel {interaction.channel.id} failed', e) self._logger.error(__name__, f'Send message to channel {interaction.channel.id} failed', e)
else: else:

View File

@ -12,8 +12,6 @@ from modules.base.command.help_command import HelpCommand
from modules.base.command.info_command import InfoCommand from modules.base.command.info_command import InfoCommand
from modules.base.command.ping_command import PingCommand from modules.base.command.ping_command import PingCommand
from modules.base.command.purge_command import PurgeCommand from modules.base.command.purge_command import PurgeCommand
from modules.base.command.restart_command import RestartCommand
from modules.base.command.shutdown_command import ShutdownCommand
from modules.base.command.user_group import UserGroup from modules.base.command.user_group import UserGroup
from modules.base.events.base_on_command_error_event import BaseOnCommandErrorEvent from modules.base.events.base_on_command_error_event import BaseOnCommandErrorEvent
from modules.base.events.base_on_command_event import BaseOnCommandEvent from modules.base.events.base_on_command_event import BaseOnCommandEvent
@ -45,8 +43,6 @@ class BaseModule(ModuleABC):
self._dc.add_command(InfoCommand) self._dc.add_command(InfoCommand)
self._dc.add_command(PingCommand) self._dc.add_command(PingCommand)
self._dc.add_command(RestartCommand)
self._dc.add_command(ShutdownCommand)
self._dc.add_command(PurgeCommand) self._dc.add_command(PurgeCommand)
self._dc.add_command(UserGroup) self._dc.add_command(UserGroup)
# events # events

View File

@ -0,0 +1 @@
# imports:

View File

@ -0,0 +1,102 @@
import os
from datetime import datetime
from zipfile import ZipFile
import discord
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.logging import LoggingSettings
from cpl_discord.command import DiscordCommandABC
from cpl_query.extension import List
from cpl_translation import TranslatePipe
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.custom_file_logger_abc import CustomFileLoggerABC
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.helper.command_checks import CommandChecks
from bot_core.logging.command_logger import CommandLogger
from modules.permission.abc.permission_service_abc import PermissionServiceABC
class LogCommand(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
logging_settings: LoggingSettings,
services: ServiceProviderABC,
message_service: MessageServiceABC,
client_utils: ClientUtilsServiceABC,
translate: TranslatePipe,
permissions: PermissionServiceABC,
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._logging_settings = logging_settings
self._services = services
self._message_service = message_service
self._client_utils = client_utils
self._t = translate
self._permissions = permissions
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
def _reduce_path(self, p: str) -> str:
if p.count('/') == 1 or p == '':
return p
return self._reduce_path(os.path.dirname(p))
@commands.hybrid_command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_technician()
async def log(self, ctx: Context):
self._logger.debug(__name__, f'Received command log {ctx}')
possible_log_paths = List(str)
possible_log_paths.append(self._reduce_path(self._logging_settings.path))
file_extensions = List(str)
if '.' in self._logging_settings.filename:
split_filename = self._logging_settings.filename.split(".")
file_extensions.append(f'.{split_filename[len(split_filename) - 1]}')
for subclass in CustomFileLoggerABC.__subclasses__():
logger: CustomFileLoggerABC = self._services.get_service(subclass)
if logger is None:
continue
path = self._reduce_path(logger.settings.path)
if '.' in logger.settings.filename:
split_filename = logger.settings.filename.split(".")
file_extension = f'.{split_filename[len(split_filename) - 1]}'
if file_extension not in file_extensions:
file_extensions.append(file_extension)
if path in possible_log_paths:
continue
possible_log_paths.append(path)
files = List(str)
for possible_path in possible_log_paths:
for r, d, f in os.walk(possible_path):
for file in f:
if '.' not in file:
continue
split_filename = file.split(".")
if f'.{split_filename[len(split_filename) - 1]}' not in file_extensions:
continue
files.append(os.path.join(r, file))
zip_file = ZipFile('logs.zip', 'w')
files.for_each(lambda x: zip_file.write(x))
zip_file.close()
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.technician.log_message'), file=discord.File(zip_file.filename, 'logs.zip'), ephemeral=True)
os.remove(zip_file.filename)
self._logger.trace(__name__, f'Finished log command')

View File

@ -44,13 +44,13 @@ class RestartCommand(DiscordCommandABC):
@commands.hybrid_command() @commands.hybrid_command()
@commands.guild_only() @commands.guild_only()
@CommandChecks.check_is_ready() @CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator() @CommandChecks.check_is_member_technician()
async def restart(self, ctx: Context): async def restart(self, ctx: Context):
self._logger.debug(__name__, f'Received command restart {ctx}') self._logger.debug(__name__, f'Received command restart {ctx}')
self._config.add_configuration('IS_RESTART', 'true') self._config.add_configuration('IS_RESTART', 'true')
await self._client_utils.presence_game('common.presence.restart') await self._client_utils.presence_game('common.presence.restart')
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.admin.restart_message')) await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.technician.restart_message'))
await asyncio.sleep(self._settings.wait_for_restart) await asyncio.sleep(self._settings.wait_for_restart)
await self._bot.stop_async() await self._bot.stop_async()

View File

@ -45,12 +45,12 @@ class ShutdownCommand(DiscordCommandABC):
@commands.hybrid_command() @commands.hybrid_command()
@commands.guild_only() @commands.guild_only()
@CommandChecks.check_is_ready() @CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator() @CommandChecks.check_is_member_technician()
async def shutdown(self, ctx: Context): async def shutdown(self, ctx: Context):
self._logger.debug(__name__, f'Received command shutdown {ctx}') self._logger.debug(__name__, f'Received command shutdown {ctx}')
await self._client_utils.presence_game('common.presence.shutdown') await self._client_utils.presence_game('common.presence.shutdown')
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.admin.shutdown_message')) await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.technician.shutdown_message'))
await asyncio.sleep(self._settings.wait_for_shutdown) await asyncio.sleep(self._settings.wait_for_shutdown)
await self._bot.stop_async() await self._bot.stop_async()

View File

@ -0,0 +1,44 @@
{
"ProjectSettings": {
"Name": "technician",
"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.0"
],
"PythonVersion": ">=3.10.6",
"PythonPath": {},
"Classifiers": []
},
"BuildSettings": {
"ProjectType": "library",
"SourcePath": "",
"OutputPath": "../../dist",
"Main": "technician.main",
"EntryPoint": "technician",
"IncludePackageData": false,
"Included": [],
"Excluded": [
"*/__pycache__",
"*/logs",
"*/tests"
],
"PackageData": {},
"ProjectReferences": []
}
}

View File

@ -0,0 +1,29 @@
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.base.abc.base_helper_abc import BaseHelperABC
from modules.technician.command.log_command import LogCommand
from modules.technician.command.restart_command import RestartCommand
from modules.technician.command.shutdown_command import ShutdownCommand
from modules.base.service.base_helper_service import BaseHelperService
class TechnicianModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.base_module)
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
pass
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_transient(BaseHelperABC, BaseHelperService)
# commands
self._dc.add_command(RestartCommand)
self._dc.add_command(ShutdownCommand)
self._dc.add_command(LogCommand)
# events