Added info command & Added dynamic embed

This commit is contained in:
Sven Heidemann 2022-01-15 16:38:15 +01:00
parent 82ba1ae904
commit 5489cc96b4
15 changed files with 273 additions and 39 deletions

View File

@ -39,6 +39,7 @@ from gismo_data.service.user_repository_service import UserRepositoryService
from modules.base.base import Base from modules.base.base import Base
from modules.base.service.afk_command_service import AFKCommandService from modules.base.service.afk_command_service import AFKCommandService
from modules.base.service.help_command_service import HelpCommandService from modules.base.service.help_command_service import HelpCommandService
from modules.base.service.info_command_service import InfoCommandService
from modules.base.service.ping_command_service import PingCommandService from modules.base.service.ping_command_service import PingCommandService
from modules.base.service.purge_command_service import PurgeCommandService from modules.base.service.purge_command_service import PurgeCommandService
from modules.boot_log.boot_log import BootLog from modules.boot_log.boot_log import BootLog
@ -101,6 +102,7 @@ class Startup(StartupABC):
services.add_singleton(CommandABC, PurgeCommandService) services.add_singleton(CommandABC, PurgeCommandService)
services.add_singleton(CommandABC, AFKCommandService) services.add_singleton(CommandABC, AFKCommandService)
services.add_singleton(CommandABC, HelpCommandService) services.add_singleton(CommandABC, HelpCommandService)
services.add_singleton(CommandABC, InfoCommandService)
# modules # modules
services.add_transient(ModuleABC, Database) services.add_transient(ModuleABC, Database)

View File

@ -1,25 +1 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'gismo_core'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.4.8'
from collections import namedtuple
# imports # imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='4', micro='8')

View File

@ -11,3 +11,6 @@ class ClientUtilsServiceABC(ABC):
@abstractmethod @abstractmethod
def moved_user(self, guild_id: int): pass def moved_user(self, guild_id: int): pass
@abstractmethod
def get_client(self, dc_ic: int, guild_id: int): pass

View File

@ -18,10 +18,10 @@ class MessageServiceABC(ABC):
async def delete_message(self, message: discord.Message): pass async def delete_message(self, message: discord.Message): pass
@abstractmethod @abstractmethod
async def send_channel_message(self, channel: discord.TextChannel, message: str): pass async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed]): pass
@abstractmethod @abstractmethod
async def send_dm_message(self, message: str, receiver: Union[discord.User, discord.Member]): pass async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member]): pass
@abstractmethod @abstractmethod
async def send_ctx_msg(self, ctx: Context, message: str, file: discord.File = None, is_persistent: bool = False): pass async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False): pass

View File

@ -0,0 +1,53 @@
import traceback
from typing import Optional
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
from cpl_query.extension import List
from gismo_core.model.embed_description import EmbedDescription
from gismo_core.model.embed_description_field import EmbedDescriptionField
class EmbedDescriptionSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._embed_description: Optional[EmbedDescription] = None
@property
def embed_description(self) -> EmbedDescription:
return self._embed_description
def from_dict(self, settings: dict):
try:
title = ''
description = ''
url = ''
color = ''
fields = List(EmbedDescriptionField)
footer = ''
for key in settings:
if key == 'Title':
title = settings[key]
elif key == 'Description':
description = settings[key]
elif key == 'URL':
url = settings[key]
elif key == 'Color':
color = settings[key]
elif key == 'Fields':
for field in settings[key]:
fields.append(EmbedDescriptionField(field['Name'], field['Value'], bool(field['Inline'])))
elif key == 'Footer':
footer = settings[key]
else:
raise Exception(f'Unexpected key {key}')
self._embed_description = EmbedDescription(title, description, url, color, fields, footer)
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@ -0,0 +1 @@
# imports

View File

@ -0,0 +1,52 @@
from cpl_query.extension import List
from gismo_core.model.embed_description_field import EmbedDescriptionField
class EmbedDescription:
def __init__(
self,
title: str = None,
description: str = None,
url: str = None,
color: str = None,
fields: List[EmbedDescriptionField] = None,
footer: str = None
):
self._title = title
self._description = description
self._url = url
self._color = color
self._fields = fields
self._footer = footer
@property
def title(self) -> str:
return self._title
@property
def description(self) -> str:
return self._description
@property
def url(self) -> str:
return self._url
@property
def color(self) -> str:
return self._color
@property
def fields(self) -> list[EmbedDescriptionField]:
return self._fields
@fields.setter
def fields(self, value: list[EmbedDescriptionField]):
self._fields = value
@property
def footer(self) -> str:
return self._footer

View File

@ -0,0 +1,27 @@
class EmbedDescriptionField:
def __init__(
self,
name: str,
value: str,
inline: bool
):
self._name = name
self._value = value
self._inline = inline
@property
def name(self) -> str:
return self._name
@property
def value(self) -> str:
return self._value
@value.setter
def value(self, value: str):
self._value = value
@property
def inline(self) -> bool:
return self._inline

View File

@ -34,3 +34,8 @@ class ClientUtilsService(ClientUtilsServiceABC):
client.moved_users_count += 1 client.moved_users_count += 1
self._clients.update_client(client) self._clients.update_client(client)
self._db.save_changes() self._db.save_changes()
def get_client(self, dc_ic: int, guild_id: int):
server = self._servers.get_server_by_discord_id(guild_id)
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.server_id)
return client

View File

@ -0,0 +1,23 @@
import discord
from gismo_core.model.embed_description import EmbedDescription
class EmbedService:
@staticmethod
def get_embed(description: EmbedDescription) -> discord.Embed:
embed = discord.Embed(
title=description.title,
url=description.url,
description=description.description,
color=int(description.color, 16)
)
for field in description.fields:
embed.add_field(name=field.name, value=field.value, inline=field.inline)
if description.footer is not None:
embed.set_footer(text=description.footer)
return embed

View File

@ -46,11 +46,14 @@ class MessageService(MessageServiceABC):
self._db.save_changes() self._db.save_changes()
self._logger.info(__name__, f'Deleted message {message}') self._logger.info(__name__, f'Deleted message {message}')
async def send_channel_message(self, channel: discord.TextChannel, message: str): async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed]):
self._logger.debug(__name__, f'Try to send message\n\t{message}\n\tto: {channel}') self._logger.debug(__name__, f'Try to send message\n\t{message}\n\tto: {channel}')
msg = None msg = None
try: try:
msg = await channel.send(message) if isinstance(message, discord.Embed):
msg = await channel.send(embed=message)
else:
msg = await channel.send(message)
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Send message to channel {channel.id} failed', e) self._logger.error(__name__, f'Send message to channel {channel.id} failed', e)
else: else:
@ -59,10 +62,13 @@ class MessageService(MessageServiceABC):
self._db.save_changes() self._db.save_changes()
await self.delete_message(msg) await self.delete_message(msg)
async def send_dm_message(self, message: str, receiver: Union[discord.User, discord.Member]): async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Try to send message\n\t{message}\n\tto: {receiver}') self._logger.debug(__name__, f'Try to send message\n\t{message}\n\tto: {receiver}')
try: try:
await receiver.send(message) if isinstance(message, discord.Embed):
msg = await receiver.send(embed=message)
else:
msg = await receiver.send(message)
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Send message to user {receiver.id} failed', e) self._logger.error(__name__, f'Send message to user {receiver.id} failed', e)
else: else:
@ -70,7 +76,7 @@ class MessageService(MessageServiceABC):
self._db.save_changes() self._db.save_changes()
self._logger.info(__name__, f'Sent message to user {receiver.id}') self._logger.info(__name__, f'Sent message to user {receiver.id}')
async def send_ctx_msg(self, ctx: Context, message: str, file: discord.File = None, is_persistent: bool = False): async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False):
if ctx is None: if ctx 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}')
@ -79,10 +85,10 @@ class MessageService(MessageServiceABC):
self._logger.debug(__name__, f'Try to send message\t\t{message}\n\tto: {ctx.channel}') self._logger.debug(__name__, f'Try to send message\t\t{message}\n\tto: {ctx.channel}')
msg = None msg = None
try: try:
if isinstance(message, discord.File): if isinstance(message, discord.Embed):
msg = await ctx.send(file=message) msg = await ctx.send(embed=message, file=file)
else: else:
msg = await ctx.send(message) msg = await ctx.send(message, file=file)
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Send message to channel {ctx.channel.id} failed', e) self._logger.error(__name__, f'Send message to channel {ctx.channel.id} failed', e)
else: else:

View File

@ -23,6 +23,7 @@ from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from modules.base.base_settings import BaseSettings from modules.base.base_settings import BaseSettings
from modules.base.service.afk_command_service import AFKCommandService from modules.base.service.afk_command_service import AFKCommandService
from modules.base.service.help_command_service import HelpCommandService from modules.base.service.help_command_service import HelpCommandService
from modules.base.service.info_command_service import InfoCommandService
from modules.base.service.ping_command_service import PingCommandService from modules.base.service.ping_command_service import PingCommandService
from modules.base.service.purge_command_service import PurgeCommandService from modules.base.service.purge_command_service import PurgeCommandService
from modules.permission.abc.permission_service_abc import PermissionServiceABC from modules.permission.abc.permission_service_abc import PermissionServiceABC
@ -53,7 +54,8 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
ping_command: PingCommandService, ping_command: PingCommandService,
purge_command: PurgeCommandService, purge_command: PurgeCommandService,
afk_command: AFKCommandService, afk_command: AFKCommandService,
help_command: HelpCommandService help_command: HelpCommandService,
info_command: InfoCommandService,
): ):
self._config = config self._config = config
self._logger = logger self._logger = logger
@ -83,6 +85,7 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
self._bot.add_cog(purge_command) self._bot.add_cog(purge_command)
self._bot.add_cog(afk_command) self._bot.add_cog(afk_command)
self._bot.add_cog(help_command) self._bot.add_cog(help_command)
self._bot.add_cog(info_command)
self._logger.info(__name__, f'Module {type(self)} loaded') self._logger.info(__name__, f'Module {type(self)} loaded')
@ -121,10 +124,10 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
settings: BaseSettings = self._get_config(member.guild.id) settings: BaseSettings = self._get_config(member.guild.id)
await self._messenger.send_dm_message(settings.welcome_message.format(member.guild.name), member) await self._messenger.send_dm_message(settings.welcome_message.format(member.guild.name), member)
for admin in self._permission_service.get_admins(): for admin in self._permission_service.get_admins(member.guild.id):
await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), admin) await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), admin)
for moderator in self._permission_service.get_moderators(): for moderator in self._permission_service.get_moderators(member.guild.id):
await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), moderator) await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), moderator)
try: try:

View File

@ -3,6 +3,8 @@ import traceback
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console from cpl_core.console import Console
from gismo_core.configuration.embed_description_settings import EmbedDescriptionSettings
class BaseSettings(ConfigurationModelABC): class BaseSettings(ConfigurationModelABC):
@ -22,6 +24,7 @@ class BaseSettings(ConfigurationModelABC):
self._afk_command_channel_missing_message: str = '' self._afk_command_channel_missing_message: str = ''
self._afk_command_move_message: str = '' self._afk_command_move_message: str = ''
self._help_command_reference_url: str = '' self._help_command_reference_url: str = ''
self._info_command_message: EmbedDescriptionSettings = EmbedDescriptionSettings()
@property @property
def welcome_message(self) -> str: def welcome_message(self) -> str:
@ -75,6 +78,10 @@ class BaseSettings(ConfigurationModelABC):
def help_command_reference_url(self) -> str: def help_command_reference_url(self) -> str:
return self._help_command_reference_url return self._help_command_reference_url
@property
def info_command_message(self) -> EmbedDescriptionSettings:
return self._info_command_message
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._welcome_message = settings['WelcomeMessage'] self._welcome_message = settings['WelcomeMessage']
@ -91,6 +98,7 @@ class BaseSettings(ConfigurationModelABC):
self._afk_command_channel_missing_message = settings['AFKCommandChannelMissingMessage'] self._afk_command_channel_missing_message = settings['AFKCommandChannelMissingMessage']
self._afk_command_move_message = settings['AFKCommandMoveMessage'] self._afk_command_move_message = settings['AFKCommandMoveMessage']
self._help_command_reference_url = settings['HelpCommandReferenceUrl'] self._help_command_reference_url = settings['HelpCommandReferenceUrl']
self._info_command_message.from_dict(settings['InfoCommandMessage'])
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings') Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@ -32,7 +32,7 @@ class HelpCommandService(CommandABC):
@commands.command() @commands.command()
async def help(self, ctx: Context, persistent_flag: str = None): async def help(self, ctx: Context, persistent_flag: str = None):
self._logger.debug(__name__, f'Received command ping {ctx}:{persistent_flag}') self._logger.debug(__name__, f'Received command help {ctx}:{persistent_flag}')
self._client_utils.received_command(ctx.guild.id) self._client_utils.received_command(ctx.guild.id)
settings: BaseSettings = self._config.get_configuration(f'Base_{ctx.guild.id}') settings: BaseSettings = self._config.get_configuration(f'Base_{ctx.guild.id}')
is_persistent = persistent_flag == '--stay' is_persistent = persistent_flag == '--stay'

View File

@ -0,0 +1,75 @@
from datetime import datetime
from cpl_core.configuration import ConfigurationABC
from cpl_core.logging import LoggerABC
from cpl_query.extension import List
from discord.ext import commands
from discord.ext.commands import Context
import gismo
from gismo_core.abc.bot_service_abc import BotServiceABC
from gismo_core.abc.client_utils_service_abc import ClientUtilsServiceABC
from gismo_core.abc.command_abc import CommandABC
from gismo_core.abc.message_service_abc import MessageServiceABC
from gismo_core.abc.module_abc import ModuleABC
from gismo_core.model.embed_description_field import EmbedDescriptionField
from gismo_core.service.embed_service import EmbedService
from modules.base.base_settings import BaseSettings
class InfoCommandService(CommandABC):
def __init__(
self,
config: ConfigurationABC,
logger: LoggerABC,
message_service: MessageServiceABC,
bot: BotServiceABC,
client_utils: ClientUtilsServiceABC
):
CommandABC.__init__(self)
self._config = config
self._logger = logger
self._message_service = message_service
self._bot = bot
self._client_utils = client_utils
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.command()
async def info(self, ctx: Context):
self._logger.debug(__name__, f'Received command info {ctx}')
self._client_utils.received_command(ctx.guild.id)
settings: BaseSettings = self._config.get_configuration(f'Base_{ctx.guild.id}')
embed_description = settings.info_command_message.embed_description
client = self._client_utils.get_client(self._bot.user.id, ctx.guild.id)
for i in range(len(embed_description.fields)):
field = embed_description.fields[i]
if field.value == '$version':
field.value = gismo.__version__
elif field.value == '$ontime':
start_time = self._config.get_configuration('Bot_StartTime')
ontime = round((datetime.now() - datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S.%f')).total_seconds()/3600, 2)
field.value = f'{ontime}h'
elif field.value == '$sent_message_count':
field.value = client.sent_message_count
elif field.value == '$received_message_count':
field.value = client.received_message_count
elif field.value == '$deleted_message_count':
field.value = client.deleted_message_count
elif field.value == '$received_command_count':
field.value = client.received_command_count
elif field.value == '$moved_users_count':
field.value = client.moved_users_count
elif field.value == '$modules':
field.value = ''
for module in ModuleABC.__subclasses__():
field.value += f'{module.__name__}\n'
await self._message_service.send_ctx_msg(
ctx,
EmbedService.get_embed(embed_description)
)
self._logger.trace(__name__, f'Finished ping command')