Moved bot to kdb-bot #70

This commit is contained in:
2022-10-15 23:17:45 +02:00
parent 029b46d7de
commit ead3f69a69
216 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3')

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base.abc'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3')

View File

@@ -0,0 +1,12 @@
from abc import abstractmethod, ABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseHelperABC(ABC):
def __init__(self):
ABC.__init__(self)
@abstractmethod
def get_config(self, g_id: int) -> BaseServerSettings: pass

View File

@@ -0,0 +1,46 @@
{
"ProjectSettings": {
"Name": "base",
"Version": {
"Major": "0",
"Minor": "0",
"Micro": "0"
},
"Author": "",
"AuthorEmail": "",
"Description": "",
"LongDescription": "",
"URL": "",
"CopyrightDate": "",
"CopyrightName": "",
"LicenseName": "",
"LicenseDescription": "",
"Dependencies": [
"cpl-core>=2022.10.0.post2"
],
"DevDependencies": [
"cpl-cli==2022.10.0"
],
"PythonVersion": ">=3.10.4",
"PythonPath": {
"linux": ""
},
"Classifiers": []
},
"BuildSettings": {
"ProjectType": "library",
"SourcePath": "",
"OutputPath": "../../dist",
"Main": "base.main",
"EntryPoint": "base",
"IncludePackageData": false,
"Included": [],
"Excluded": [
"*/__pycache__",
"*/logs",
"*/tests"
],
"PackageData": {},
"ProjectReferences": []
}
}

View File

@@ -0,0 +1,44 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
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.base.command.afk_command import AFKCommand
from modules.base.command.help_command import HelpCommand
from modules.base.command.info_command import InfoCommand
from modules.base.command.ping_command import PingCommand
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_member_join_event import BaseOnMemberJoinEvent
from modules.base.events.base_on_member_remove_event import BaseOnMemberRemoveEvent
from modules.base.events.base_on_message_event import BaseOnMessageEvent
from modules.base.events.base_on_voice_state_update_event import BaseOnVoiceStateUpdateEvent
from modules.base.service.base_helper_service import BaseHelperService
class BaseModule(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(AFKCommand)
self._dc.add_command(HelpCommand)
self._dc.add_command(InfoCommand)
self._dc.add_command(PingCommand)
# events
self._dc.add_event(DiscordEventTypesEnum.on_command.value, BaseOnCommandEvent)
self._dc.add_event(DiscordEventTypesEnum.on_command_error.value, BaseOnCommandErrorEvent)
self._dc.add_event(DiscordEventTypesEnum.on_member_join.value, BaseOnMemberJoinEvent)
self._dc.add_event(DiscordEventTypesEnum.on_member_remove.value, BaseOnMemberRemoveEvent)
self._dc.add_event(DiscordEventTypesEnum.on_message.value, BaseOnMessageEvent)
self._dc.add_event(DiscordEventTypesEnum.on_voice_state_update.value, BaseOnVoiceStateUpdateEvent)

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base.command'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3')

View File

@@ -0,0 +1,60 @@
from cpl_core.configuration import ConfigurationABC
from cpl_discord.command import DiscordCommandABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord import VoiceChannel
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 modules.base.configuration.base_server_settings import BaseServerSettings
class AFKCommand(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
config: ConfigurationABC,
message_service: MessageServiceABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsServiceABC,
translate: TranslatePipe
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._config = config
self._message_service = message_service
self._bot = bot
self._client_utils = client_utils
self._t = translate
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.hybrid_command()
@commands.guild_only()
async def afk(self, ctx: Context):
self._logger.debug(__name__, f'Received command afk {ctx}')
if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx):
return
self._client_utils.received_command(ctx.guild.id)
settings: BaseServerSettings = self._config.get_configuration(f'BaseServerSettings_{ctx.guild.id}')
if ctx.author.voice is None or ctx.author.voice.channel is None:
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.afk_command_channel_missing_message'))
self._logger.trace(__name__, f'Finished afk command')
return
self._bot.loop.create_task(self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.afk_command_move_message')))
channel: VoiceChannel = ctx.guild.get_channel(settings.afk_command_channel_id)
try:
await ctx.author.move_to(channel)
self._client_utils.moved_user(ctx.guild.id)
except Exception as e:
self._logger.error(__name__, f'Cannot move user {ctx.author.id} to channel {ctx.channel.id}', e)
await self._message_service.send_ctx_msg(ctx, self._t.transform('common.no_permission_message'))
self._logger.trace(__name__, f'Finished afk command')

View File

@@ -0,0 +1,52 @@
from typing import List
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_discord.command import DiscordCommandABC
from cpl_discord.service import DiscordBotServiceABC
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 modules.base.configuration.base_server_settings import BaseServerSettings
class HelpCommand(DiscordCommandABC):
def __init__(
self,
config: ConfigurationABC,
logger: CommandLogger,
message_service: MessageServiceABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsServiceABC
):
DiscordCommandABC.__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.hybrid_command()
@commands.guild_only()
async def help(self, ctx: Context, persistent_flag: str = None):
self._logger.debug(__name__, f'Received command help {ctx}:{persistent_flag}')
if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx):
return
self._client_utils.received_command(ctx.guild.id)
settings: BaseServerSettings = self._config.get_configuration(f'BaseServerSettings_{ctx.guild.id}')
is_persistent = persistent_flag == '--stay'
await self._message_service.send_ctx_msg(ctx, settings.help_command_reference_url, is_persistent=is_persistent)
self._logger.trace(__name__, f'Finished help command')
@help.autocomplete('persistent_flag')
async def help_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
flags = ['--stay']
return [app_commands.Choice(name=key, value=key) for key in flags]

View File

@@ -0,0 +1,69 @@
from datetime import datetime
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_discord.command import DiscordCommandABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord.ext import commands
from discord.ext.commands import Context
import bot
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
class InfoCommand(DiscordCommandABC):
def __init__(
self,
config: ConfigurationABC,
logger: CommandLogger,
message_service: MessageServiceABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsServiceABC,
translate: TranslatePipe
):
DiscordCommandABC.__init__(self)
self._config = config
self._logger = logger
self._message_service = message_service
self._bot = bot
self._client_utils = client_utils
self._t = translate
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.hybrid_command()
@commands.guild_only()
async def info(self, ctx: Context, *, wait: int = None):
self._logger.debug(__name__, f'Received command info {ctx},{wait}')
if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx):
return
self._client_utils.received_command(ctx.guild.id)
client = self._client_utils.get_client(self._bot.user.id, ctx.guild.id)
embed = discord.Embed(
title=self._t.transform('modules.base.info.title'),
description=self._t.transform('modules.base.info.description'),
color=int('ef9d0d', 16)
)
embed.add_field(name=self._t.transform('modules.base.info.fields.version'), value=bot.__version__)
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)
embed.add_field(name=self._t.transform('modules.base.info.fields.ontime'), value=f'{ontime}h')
embed.add_field(name=self._t.transform('modules.base.info.fields.sent_message_count'), value=client.sent_message_count, inline=False)
embed.add_field(name=self._t.transform('modules.base.info.fields.received_message_count'), value=client.received_message_count)
embed.add_field(name=self._t.transform('modules.base.info.fields.deleted_message_count'), value=client.deleted_message_count, inline=False)
embed.add_field(name=self._t.transform('modules.base.info.fields.received_command_count'), value=client.received_command_count)
embed.add_field(name=self._t.transform('modules.base.info.fields.moved_users_count'), value=client.moved_users_count)
from bot.module_list import ModuleList
modules = ModuleList.get_modules()
modules = modules.select(lambda x: x.__name__.replace('Module', ''))
embed.add_field(name=self._t.transform('modules.base.info.fields.modules'), value='\n'.join(modules), inline=False)
await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait)
self._logger.trace(__name__, f'Finished info command')

View File

@@ -0,0 +1,40 @@
from cpl_discord.command import DiscordCommandABC
from cpl_discord.service import DiscordBotServiceABC
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.message_service_abc import MessageServiceABC
from bot_core.logging.command_logger import CommandLogger
class PingCommand(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
message_service: MessageServiceABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsServiceABC,
translate: TranslatePipe
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._message_service = message_service
self._bot = bot
self._client_utils = client_utils
self._t = translate
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.hybrid_command()
@commands.guild_only()
async def ping(self, ctx: Context):
self._logger.debug(__name__, f'Received command ping {ctx}')
if not await self._client_utils.check_if_bot_is_ready_yet_and_respond(ctx):
return
self._client_utils.received_command(ctx.guild.id)
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.pong'))
self._logger.trace(__name__, f'Finished ping command')

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base.configuration'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3')

View File

@@ -0,0 +1,61 @@
import traceback
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
from cpl_query.extension import List
class BaseServerSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._id: int = 0
self._max_voice_state_hours: int = 0
self._xp_per_message: int = 0
self._xp_per_ontime_hour: int = 0
self._afk_channel_ids: List[int] = List(int)
self._afk_command_channel_id: int = 0
self._help_command_reference_url: str = ''
@property
def id(self) -> int:
return self._id
@property
def max_voice_state_hours(self) -> int:
return self._max_voice_state_hours
@property
def xp_per_message(self) -> int:
return self._xp_per_message
@property
def xp_per_ontime_hour(self) -> int:
return self._xp_per_ontime_hour
@property
def afk_channel_ids(self) -> List[int]:
return self._afk_channel_ids
@property
def afk_command_channel_id(self) -> int:
return self._afk_command_channel_id
@property
def help_command_reference_url(self) -> str:
return self._help_command_reference_url
def from_dict(self, settings: dict):
try:
self._id = int(settings['Id'])
self._max_voice_state_hours = int(settings['MaxVoiceStateHours'])
self._xp_per_message = int(settings['XpPerMessage'])
self._xp_per_ontime_hour = int(settings['XpPerOntimeHour'])
for index in settings['AFKChannelIds']:
self._afk_channel_ids.append(int(index))
self._afk_command_channel_id = settings['AFKCommandChannelId']
self._help_command_reference_url = settings['HelpCommandReferenceUrl']
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@@ -0,0 +1,32 @@
import traceback
from cpl_core.configuration import ConfigurationModelABC
from cpl_core.console import Console
from cpl_query.extension import List
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._servers: List[BaseServerSettings] = List()
@property
def servers(self) -> List[BaseServerSettings]:
return self._servers
def from_dict(self, settings: dict):
try:
servers = List(BaseServerSettings)
for s in settings:
st = BaseServerSettings()
settings[s]['Id'] = s
st.from_dict(settings[s])
servers.append(st)
self._servers = servers
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base.events'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3')

View File

@@ -0,0 +1,146 @@
import datetime
import traceback
import uuid
from cpl_core.time import TimeFormatSettings
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord.ext import commands
from discord.ext.commands import Context, CommandError
from cpl_core.logging import LoggerABC
from cpl_discord.events.on_command_error_abc import OnCommandErrorABC
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.configuration.bot_settings import BotSettings
class BaseOnCommandErrorEvent(OnCommandErrorABC):
def __init__(
self,
logger: LoggerABC,
bot: DiscordBotServiceABC,
messenger: MessageServiceABC,
bot_settings: BotSettings,
time_format_settings: TimeFormatSettings,
translate: TranslatePipe
):
OnCommandErrorABC.__init__(self)
self._logger = logger
self._bot = bot
self._messenger = messenger
self._bot_settings = bot_settings
self._time_format_settings = time_format_settings
self._t = translate
async def on_command_error(self, ctx: Context, error: CommandError):
error = getattr(error, 'original', error)
uid = uuid.uuid4()
self._logger.error(__name__, f'Got error: {type(error).__name__} UID: {uid}')
if isinstance(error, commands.MissingRequiredArgument):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.missing_required_argument'), without_tracking=True)
elif isinstance(error, commands.ArgumentParsingError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.argument_parsing_error'), without_tracking=True)
elif isinstance(error, commands.UnexpectedQuoteError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.unexpected_quote_error'), without_tracking=True)
elif isinstance(error, commands.InvalidEndOfQuotedStringError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.invalid_end_of_quoted_string_error'), without_tracking=True)
elif isinstance(error, commands.ExpectedClosingQuoteError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.expected_closing_quote_error'), without_tracking=True)
elif isinstance(error, commands.BadArgument):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.bad_argument'), without_tracking=True)
elif isinstance(error, commands.BadUnionArgument):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.bad_union_argument'), without_tracking=True)
elif isinstance(error, commands.PrivateMessageOnly):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.private_message_only'), without_tracking=True)
elif isinstance(error, commands.NoPrivateMessage):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.no_private_message'), without_tracking=True)
elif isinstance(error, commands.CheckFailure):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.check_failure'), without_tracking=True)
elif isinstance(error, commands.CheckAnyFailure):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.check_any_failure'), without_tracking=True)
elif isinstance(error, commands.CommandNotFound):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.command_not_found'), without_tracking=True)
elif isinstance(error, commands.DisabledCommand):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.disabled_command'), without_tracking=True)
elif isinstance(error, commands.CommandInvokeError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.command_invoke_error'), without_tracking=True)
elif isinstance(error, commands.TooManyArguments):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.too_many_arguments'), without_tracking=True)
elif isinstance(error, commands.UserInputError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.user_input_error'), without_tracking=True)
elif isinstance(error, commands.CommandOnCooldown):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.command_on_cooldown'), without_tracking=True)
elif isinstance(error, commands.MaxConcurrencyReached):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.max_concurrency_reached'), without_tracking=True)
elif isinstance(error, commands.NotOwner):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.not_owner'), without_tracking=True)
elif isinstance(error, commands.MissingPermissions):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.missing_permissions'), without_tracking=True)
elif isinstance(error, commands.BotMissingPermissions):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.bot_missing_permissions'), without_tracking=True)
elif isinstance(error, commands.MissingRole):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.missing_role'), without_tracking=True)
elif isinstance(error, commands.BotMissingRole):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.bot_missing_role'), without_tracking=True)
elif isinstance(error, commands.MissingAnyRole):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.missing_any_role'), without_tracking=True)
elif isinstance(error, commands.BotMissingAnyRole):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.bot_missing_any_role'), without_tracking=True)
elif isinstance(error, commands.NSFWChannelRequired):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.nsfw_channel_required'), without_tracking=True)
elif isinstance(error, commands.ExtensionError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.extension_error'), without_tracking=True)
elif isinstance(error, commands.ExtensionAlreadyLoaded):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.extension_already_loaded'), without_tracking=True)
elif isinstance(error, commands.ExtensionNotLoaded):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.extension_not_loaded'), without_tracking=True)
elif isinstance(error, commands.NoEntryPointError):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.no_entry_point_error'), without_tracking=True)
elif isinstance(error, commands.ExtensionFailed):
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.extension_failed'), without_tracking=True)
else:
await self._messenger.send_ctx_msg(ctx, self._t.transform('common.errors.command_error'), without_tracking=True)
message = self._t.transform('modules.base.technician_command_error_message').format(
ctx.command,
ctx.author,
error,
datetime.datetime.now().strftime(self._time_format_settings.date_time_format),
uid
)
for t in self._bot_settings.technicians:
member = self._bot.get_user(t)
await self._messenger.send_dm_message(message, member, without_tracking=True)

View File

@@ -0,0 +1,90 @@
from typing import Optional
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_core.time import TimeFormatSettings
from cpl_discord.events import OnCommandABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord.ext.commands import Context
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.configuration.bot_settings import BotSettings
from bot_core.logging.command_logger import CommandLogger
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.user import User
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseOnCommandEvent(OnCommandABC):
def __init__(
self,
logger: CommandLogger,
bot: DiscordBotServiceABC,
messenger: MessageServiceABC,
bot_settings: BotSettings,
time_format_settings: TimeFormatSettings,
translate: TranslatePipe,
bhs: BaseHelperABC,
db: DatabaseContextABC,
users: UserRepositoryABC,
clients: ClientRepositoryABC,
servers: ServerRepositoryABC,
):
OnCommandABC.__init__(self)
self._logger = logger
self._bot = bot
self._messenger = messenger
self._bot_settings = bot_settings
self._time_format_settings = time_format_settings
self._t = translate
self._base_helper = bhs
self._db = db
self._users = users
self._clients = clients
self._servers = servers
def _append_received_command_count(self, g_id: int):
try:
self._clients.append_received_command_count(self._bot.user.id, g_id, 1)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot edit client {self._bot.user.id}@{g_id}', e)
def _handle_message_for_xp(self, message: discord.Message):
dc_user_id = message.author.id
try:
server = self._servers.get_server_by_discord_id(message.guild.id)
except Exception as e:
self._logger.error(__name__, f'Cannot get server {message.guild.id}', e)
return
user: Optional[User] = None
try:
user = self._users.get_user_by_discord_id_and_server_id(dc_user_id, server.server_id)
except Exception as e:
self._logger.error(__name__, f'Cannot get user {dc_user_id}', e)
return
if user is None:
self._logger.error(__name__, f'User not found {dc_user_id}')
return
settings: BaseServerSettings = self._base_helper.get_config(message.guild.id)
old_xp = user.xp
user.xp += settings.xp_per_message
self._users.update_user(user)
self._db.save_changes()
self._logger.debug(__name__, f'User {user} sent message. xp: from {old_xp} to {user.xp}')
async def on_command(self, ctx: Context):
self._logger.debug(__name__, f'Module {type(self)} started')
self._logger.info(__name__, f'Received command: {ctx.command} from {ctx.channel}')
if ctx is None or ctx.guild is None:
return
self._append_received_command_count(ctx.guild.id)

View File

@@ -0,0 +1,97 @@
from datetime import datetime
from typing import Union
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnMemberJoinABC
from cpl_translation import TranslatePipe
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
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_repository_abc import UserRepositoryABC
from bot_data.model.known_user import KnownUser
from bot_data.model.user import User
from bot_data.model.user_joined_server import UserJoinedServer
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.configuration.base_server_settings import BaseServerSettings
from modules.permission.abc.permission_service_abc import PermissionServiceABC
class BaseOnMemberJoinEvent(OnMemberJoinABC):
def __init__(
self,
config: ConfigurationABC,
logger: LoggerABC,
base_helper: BaseHelperABC,
messenger: MessageServiceABC,
permissions: PermissionServiceABC,
db: DatabaseContextABC,
known_users: KnownUserRepositoryABC,
users: UserRepositoryABC,
servers: ServerRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
translate: TranslatePipe
):
OnMemberJoinABC.__init__(self)
self._config = config
self._logger = logger
self._base_helper = base_helper
self._messenger = messenger
self._permission_service = permissions
self._db = db
self._known_users = known_users
self._users = users
self._servers = servers
self._user_joins = user_joins
self._t = translate
def _check_for_known_user(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Check if user is already known {member}')
try:
user = self._known_users.find_user_by_discord_id(member.id)
if user is not None:
return
self._logger.debug(__name__, f'Add user: {member.id}')
self._known_users.add_user(KnownUser(member.id))
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get user {member.id}', e)
async def _add_if_not_exists_user_async(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Check if user exists {member}')
settings: BaseServerSettings = self._base_helper.get_config(member.guild.id)
await self._messenger.send_dm_message(self._t.transform('modules.base.welcome_message').format(member.guild.name), member)
for admin in self._permission_service.get_admins(member.guild.id):
await self._messenger.send_dm_message(self._t.transform('modules.base.welcome_message_for_team').format(member.name), admin)
for moderator in self._permission_service.get_moderators(member.guild.id):
await self._messenger.send_dm_message(self._t.transform('modules.base.welcome_message_for_team').format(member.name), moderator)
try:
server = self._servers.get_server_by_discord_id(member.guild.id)
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
if user is not None:
self._user_joins.add_user_joined_server(UserJoinedServer(user, datetime.now()))
return
self._logger.debug(__name__, f'Add user: {member.id}')
self._users.add_user(User(member.id, 0, server))
self._db.save_changes()
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.server_id)
self._user_joins.add_user_joined_server(UserJoinedServer(user, datetime.now()))
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get user {member.id}', e)
async def on_member_join(self, member: discord.Member):
self._logger.debug(__name__, f'Module {type(self)} started')
self._check_for_known_user(member)
await self._add_if_not_exists_user_async(member)

View File

@@ -0,0 +1,64 @@
from datetime import datetime
from typing import Union
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnMemberRemoveABC
from cpl_translation import TranslatePipe
from bot_core.abc.message_service_abc import MessageServiceABC
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_repository_abc import UserRepositoryABC
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseOnMemberRemoveEvent(OnMemberRemoveABC):
def __init__(
self,
logger: LoggerABC,
base_helper: BaseHelperABC,
db: DatabaseContextABC,
messenger: MessageServiceABC,
users: UserRepositoryABC,
servers: ServerRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
translate: TranslatePipe
):
OnMemberRemoveABC.__init__(self)
self._logger = logger
self._base_helper = base_helper
self._db = db
self._messenger = messenger
self._users = users
self._servers = servers
self._user_joins = user_joins
self._t = translate
async def _remove_user(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Remove user {member}')
settings: BaseServerSettings = self._base_helper.get_config(member.guild.id)
await self._messenger.send_dm_message(self._t.transform('modules.base.goodbye_message'), member)
try:
server = self._servers.get_server_by_discord_id(member.guild.id)
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
if user is None:
self._logger.error(__name__, f'Cannot find user {member}')
return
join = self._user_joins.get_active_user_joined_server_by_user_id(user.user_id)
join.leaved_on = datetime.now()
self._user_joins.update_user_joined_server(join)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get user {member.id}', e)
async def on_member_remove(self, member: discord.Member):
self._logger.debug(__name__, f'Module {type(self)} started')
await self._remove_user(member)

View File

@@ -0,0 +1,81 @@
from typing import Optional
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.events import OnMessageABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.helper.log_message_helper import LogMessageHelper
from bot_core.logging.message_logger import MessageLogger
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.user import User
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseOnMessageEvent(OnMessageABC):
def __init__(
self,
logger: MessageLogger,
bhs: BaseHelperABC,
db: DatabaseContextABC,
bot: DiscordBotServiceABC,
users: UserRepositoryABC,
clients: ClientRepositoryABC,
servers: ServerRepositoryABC,
):
OnMessageABC.__init__(self)
self._logger = logger
self._base_helper = bhs
self._db = db
self._bot = bot
self._users = users
self._clients = clients
self._servers = servers
def _append_received_message_count(self, g_id: int):
try:
self._clients.append_received_message_count(self._bot.user.id, g_id, 1)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot edit client {self._bot.user.id}@{g_id}', e)
def _handle_message_for_xp(self, message: discord.Message):
dc_user_id = message.author.id
try:
server = self._servers.get_server_by_discord_id(message.guild.id)
except Exception as e:
self._logger.error(__name__, f'Cannot get server {message.guild.id}', e)
return
user: Optional[User] = None
try:
user = self._users.find_user_by_discord_id_and_server_id(dc_user_id, server.server_id)
except Exception as e:
self._logger.error(__name__, f'Cannot get user {dc_user_id}', e)
return
if user is None:
self._logger.error(__name__, f'User not found {dc_user_id}')
return
settings: BaseServerSettings = self._base_helper.get_config(message.guild.id)
old_xp = user.xp
user.xp += settings.xp_per_message
self._users.update_user(user)
self._db.save_changes()
self._logger.debug(__name__, f'User {user} sent message. xp: from {old_xp} to {user.xp}')
async def on_message(self, message: discord.Message):
self._logger.debug(__name__, f'Module {type(self)} started')
self._logger.info(__name__, f'Received message: {LogMessageHelper.get_log_string(message)}')
if message is None or message.guild is None:
return
self._append_received_message_count(message.guild.id)
if not message.author.bot:
self._handle_message_for_xp(message)

View File

@@ -0,0 +1,118 @@
from datetime import datetime
from typing import Optional
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnVoiceStateUpdateABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
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.server import Server
from bot_data.model.user import User
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
def __init__(
self,
config: ConfigurationABC,
logger: LoggerABC,
base_helper: BaseHelperABC,
servers: ServerRepositoryABC,
known_users: KnownUserRepositoryABC,
users: UserRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
db: DatabaseContextABC,
):
OnVoiceStateUpdateABC.__init__(self)
self._config = config
self._logger = logger
self._base_helper = base_helper
self._servers = servers
self._known_users = known_users
self._users = users
self._user_joins = user_joins
self._user_joins_vc = user_joins_vc
self._db = db
self._logger.info(__name__, f'Module {type(self)} loaded')
def _update_voice_state(self, joined: bool, dc_user_id: int, dc_channel_id: int, server: Server):
user: Optional[User] = None
try:
user = self._users.get_user_by_discord_id_and_server_id(dc_user_id, server.server_id)
except Exception as e:
self._logger.error(__name__, f'Cannot get user {dc_user_id}', e)
return
if user is None:
self._logger.error(__name__, f'User not found {dc_user_id}')
return
try:
if joined:
join = UserJoinedVoiceChannel(user, dc_channel_id, datetime.now())
self._user_joins_vc.add_user_joined_voice_channel(join)
self._db.save_changes()
return
settings: BaseServerSettings = self._base_helper.get_config(server.discord_server_id)
join = self._user_joins_vc.get_active_user_joined_voice_channel_by_user_id(user.user_id)
join.leaved_on = datetime.now()
# ontime as hours
ontime = round((join.leaved_on - join.joined_on).total_seconds() / 3600, 2)
old_xp = user.xp
user.xp += round(ontime * settings.xp_per_ontime_hour)
self._user_joins_vc.update_user_joined_voice_channel(join)
self._users.update_user(user)
self._db.save_changes()
self._logger.debug(__name__, f'User {user} leaved_on {join.leaved_on}. Ontime: {ontime}h | xp: from {old_xp} to {user.xp}')
except Exception as e:
self._logger.error(__name__, f'Ontime validation failed', e)
async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState):
self._logger.debug(__name__, f'Module {type(self)} started')
self._logger.trace(__name__, f'Detected on_voice_state_update {member.id} from {before} to {after}')
settings: BaseServerSettings = self._base_helper.get_config(member.guild.id)
server = self._servers.get_server_by_discord_id(member.guild.id)
try:
# join
if before.channel is None and after.channel is not None and after.channel.id not in settings.afk_channel_ids:
self._logger.trace(__name__, f'User {member.id} joined {after.channel}')
self._update_voice_state(True, member.id, after.channel.id, server)
# leave
elif before.channel is not None and after.channel is None and before.channel.id not in settings.afk_channel_ids:
self._logger.trace(__name__, f'User {member.id} left {before.channel}')
self._update_voice_state(False, member.id, before.channel.id, server)
# channel to channel
elif before.channel is not None and after.channel is not None:
# joined
if before.channel.id in settings.afk_channel_ids and after.channel.id not in settings.afk_channel_ids:
self._logger.trace(__name__, f'User {member.id} joined {after.channel}')
self._update_voice_state(True, member.id, after.channel.id, server)
# left
elif after.channel.id in settings.afk_channel_ids and before.channel.id not in settings.afk_channel_ids:
self._logger.trace(__name__, f'User {member.id} left {before.channel}')
self._update_voice_state(False, member.id, before.channel.id, server)
else:
self._logger.trace(__name__, f'User {member.id} switched to {after.channel}')
except Exception as e:
self._logger.error(__name__, f'Cannot handle voice state for user {member.id}', e)

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base.service'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3')

View File

@@ -0,0 +1,14 @@
from cpl_core.configuration import ConfigurationABC
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class BaseHelperService(BaseHelperABC):
def __init__(self, config: ConfigurationABC):
BaseHelperABC.__init__(self)
self._config = config
def get_config(self, g_id: int) -> BaseServerSettings:
return self._config.get_configuration(f'BaseServerSettings_{g_id}')