diff --git a/src/cpl_core/__init__.py b/src/cpl_core/__init__.py index 81945db0..71622c98 100644 --- a/src/cpl_core/__init__.py +++ b/src/cpl_core/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/application/__init__.py b/src/cpl_core/application/__init__.py index 3770c81f..703f706a 100644 --- a/src/cpl_core/application/__init__.py +++ b/src/cpl_core/application/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.application' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -29,4 +29,4 @@ from .startup_abc import StartupABC from .startup_extension_abc import StartupExtensionABC VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/configuration/__init__.py b/src/cpl_core/configuration/__init__.py index b596a6a9..4ba0e62a 100644 --- a/src/cpl_core/configuration/__init__.py +++ b/src/cpl_core/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.configuration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -35,4 +35,4 @@ from .validator_abc import ValidatorABC from .variable_argument import VariableArgument VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/console/__init__.py b/src/cpl_core/console/__init__.py index bf3a5d7d..da736161 100644 --- a/src/cpl_core/console/__init__.py +++ b/src/cpl_core/console/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.console' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -28,4 +28,4 @@ from .foreground_color_enum import ForegroundColorEnum from .spinner_thread import SpinnerThread VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/cpl-core.json b/src/cpl_core/cpl-core.json index 969de04a..55e50385 100644 --- a/src/cpl_core/cpl-core.json +++ b/src/cpl_core/cpl-core.json @@ -4,7 +4,7 @@ "Version": { "Major": "2022", "Minor": "7", - "Micro": "0" + "Micro": "0.post1" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/src/cpl_core/database/__init__.py b/src/cpl_core/database/__init__.py index bf073307..2f3db90f 100644 --- a/src/cpl_core/database/__init__.py +++ b/src/cpl_core/database/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.database' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -26,4 +26,4 @@ from .database_settings import DatabaseSettings from .table_abc import TableABC VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/database/connection/__init__.py b/src/cpl_core/database/connection/__init__.py index e50b869d..693e0c7d 100644 --- a/src/cpl_core/database/connection/__init__.py +++ b/src/cpl_core/database/connection/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.database.connection' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -25,4 +25,4 @@ from .database_connection import DatabaseConnection from .database_connection_abc import DatabaseConnectionABC VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/database/context/__init__.py b/src/cpl_core/database/context/__init__.py index 3494c1ba..8e7d6ea9 100644 --- a/src/cpl_core/database/context/__init__.py +++ b/src/cpl_core/database/context/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.database.context' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -25,4 +25,4 @@ from .database_context import DatabaseContext from .database_context_abc import DatabaseContextABC VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/dependency_injection/__init__.py b/src/cpl_core/dependency_injection/__init__.py index 0ed934eb..d779a3b5 100644 --- a/src/cpl_core/dependency_injection/__init__.py +++ b/src/cpl_core/dependency_injection/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.dependency_injection' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -31,4 +31,4 @@ from .service_provider import ServiceProvider from .service_provider_abc import ServiceProviderABC VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/dependency_injection/service_collection_abc.py b/src/cpl_core/dependency_injection/service_collection_abc.py index 604b6ac3..a8d5c6a3 100644 --- a/src/cpl_core/dependency_injection/service_collection_abc.py +++ b/src/cpl_core/dependency_injection/service_collection_abc.py @@ -35,6 +35,11 @@ class ServiceCollectionABC(ABC): r"""Adds the CPL internal pipes as transient""" pass + def add_discord(self): + r"""Adds the CPL discord""" + raise NotImplementedError('You should install and use the cpl-discord package') + pass + def add_translation(self): r"""Adds the CPL translation""" raise NotImplementedError('You should install and use the cpl-translation package') diff --git a/src/cpl_core/environment/__init__.py b/src/cpl_core/environment/__init__.py index 79a9c218..1c47e07a 100644 --- a/src/cpl_core/environment/__init__.py +++ b/src/cpl_core/environment/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.environment' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -26,4 +26,4 @@ from .environment_name_enum import EnvironmentNameEnum from .application_environment import ApplicationEnvironment VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/logging/__init__.py b/src/cpl_core/logging/__init__.py index 05d4b1d6..d5e56187 100644 --- a/src/cpl_core/logging/__init__.py +++ b/src/cpl_core/logging/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.logging' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -28,4 +28,4 @@ from .logging_settings import LoggingSettings from .logging_settings_name_enum import LoggingSettingsNameEnum VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/mailing/__init__.py b/src/cpl_core/mailing/__init__.py index 55787a9f..f9d0ca79 100644 --- a/src/cpl_core/mailing/__init__.py +++ b/src/cpl_core/mailing/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.mailing' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -28,4 +28,4 @@ from .email_client_settings import EMailClientSettings from .email_client_settings_name_enum import EMailClientSettingsNameEnum VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/pipes/__init__.py b/src/cpl_core/pipes/__init__.py index 478cfa06..713d7853 100644 --- a/src/cpl_core/pipes/__init__.py +++ b/src/cpl_core/pipes/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.pipes' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -30,4 +30,4 @@ from .to_camel_case_pipe import ToCamelCasePipe from .to_snake_case_pipe import ToSnakeCasePipe VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/time/__init__.py b/src/cpl_core/time/__init__.py index 6d8c2e29..75b42535 100644 --- a/src/cpl_core/time/__init__.py +++ b/src/cpl_core/time/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.time' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -25,4 +25,4 @@ from .time_format_settings import TimeFormatSettings from .time_format_settings_names_enum import TimeFormatSettingsNamesEnum VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_core/utils/__init__.py b/src/cpl_core/utils/__init__.py index 2d3c8bc4..132c8a87 100644 --- a/src/cpl_core/utils/__init__.py +++ b/src/cpl_core/utils/__init__.py @@ -15,7 +15,7 @@ __title__ = 'cpl_core.utils' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.7.0' +__version__ = '2022.7.0.post1' from collections import namedtuple @@ -26,4 +26,4 @@ from .string import String from .pip import Pip VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='7', micro='0') +version_info = VersionInfo(major='2022', minor='7', micro='0.post1') diff --git a/src/cpl_discord/__init__.py b/src/cpl_discord/__init__.py index 425ab6c1..07496ab8 100644 --- a/src/cpl_discord/__init__.py +++ b/src/cpl_discord/__init__.py @@ -1 +1,33 @@ # imports +# build-ignore + + +def add_discord(self): + from cpl_core.console import Console + from cpl_discord.service.discord_bot_service_abc import DiscordBotServiceABC + from cpl_discord.service.discord_bot_service import DiscordBotService + from cpl_discord.service.discord_service_abc import DiscordServiceABC + from cpl_discord.service.discord_service import DiscordService + + try: + self.add_singleton(DiscordServiceABC, DiscordService) + self.add_singleton(DiscordBotServiceABC, DiscordBotService) + except ImportError as e: + Console.error('cpl-discord is not installed', str(e)) + + +def init(): + from cpl_core.dependency_injection import ServiceCollection + ServiceCollection.add_discord = add_discord + + +init() + + +def get_discord_collection(services: 'ServiceCollectionABC') -> 'DiscordCollectionABC': + from cpl_discord.service.discord_collection import DiscordCollection + from cpl_discord.service.discord_collection_abc import DiscordCollectionABC + collection = DiscordCollection(services) + services.add_singleton(DiscordCollectionABC, collection) + return collection +# build-ignore-end diff --git a/src/cpl_discord/application/__init__.py b/src/cpl_discord/application/__init__.py new file mode 100644 index 00000000..425ab6c1 --- /dev/null +++ b/src/cpl_discord/application/__init__.py @@ -0,0 +1 @@ +# imports diff --git a/src/cpl_discord/application/discord_bot_abc.py b/src/cpl_discord/application/discord_bot_abc.py new file mode 100644 index 00000000..d12f2552 --- /dev/null +++ b/src/cpl_discord/application/discord_bot_abc.py @@ -0,0 +1,12 @@ +from abc import abstractmethod + +from cpl_core.application import ApplicationABC + + +class DiscordBotApplicationABC(ApplicationABC): + + def __init__(self): + pass + + @abstractmethod + def stop_async(self): pass diff --git a/src/cpl_discord/command/command_abc.py b/src/cpl_discord/command/discord_command_abc.py similarity index 50% rename from src/cpl_discord/command/command_abc.py rename to src/cpl_discord/command/discord_command_abc.py index b8dc17ca..19e3290c 100644 --- a/src/cpl_discord/command/command_abc.py +++ b/src/cpl_discord/command/discord_command_abc.py @@ -2,10 +2,10 @@ from abc import ABC, abstractmethod from discord.ext import commands -from commands_meta import CommandsMeta +from discord_commands_meta import DiscordCogMeta -class CommandABC(ABC, commands.Cog, metaclass=CommandsMeta): +class DiscordCommandABC(ABC, commands.Cog, metaclass=DiscordCogMeta): @abstractmethod def __init__(self): pass diff --git a/src/cpl_discord/command/commands_meta.py b/src/cpl_discord/command/discord_commands_meta.py similarity index 52% rename from src/cpl_discord/command/commands_meta.py rename to src/cpl_discord/command/discord_commands_meta.py index 8b66f164..9a32b758 100644 --- a/src/cpl_discord/command/commands_meta.py +++ b/src/cpl_discord/command/discord_commands_meta.py @@ -2,4 +2,4 @@ from abc import ABCMeta from discord.ext import commands -class CommandsMeta(ABCMeta, commands.CogMeta): pass +class DiscordCogMeta(ABCMeta, commands.CogMeta): pass diff --git a/src/cpl_discord/configuration/bot_settings.py b/src/cpl_discord/configuration/discord_bot_settings.py similarity index 93% rename from src/cpl_discord/configuration/bot_settings.py rename to src/cpl_discord/configuration/discord_bot_settings.py index 7b151d36..1a1581c8 100644 --- a/src/cpl_discord/configuration/bot_settings.py +++ b/src/cpl_discord/configuration/discord_bot_settings.py @@ -4,7 +4,7 @@ from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC from cpl_core.console import Console -class BotSettings(ConfigurationModelABC): +class DiscordBotSettings(ConfigurationModelABC): def __init__(self): ConfigurationModelABC.__init__(self) diff --git a/src/cpl_discord/event_types_enum.py b/src/cpl_discord/event_types_enum.py new file mode 100644 index 00000000..a028ac52 --- /dev/null +++ b/src/cpl_discord/event_types_enum.py @@ -0,0 +1,98 @@ +from enum import Enum + +from cpl_discord.events.on_bulk_message_delete_abc import OnBulkMessageDeleteABC +from cpl_discord.events.on_connect_abc import OnConnectABC +from cpl_discord.events.on_disconnect_abc import OnDisconnectABC +from cpl_discord.events.on_group_join_abc import OnGroupJoinABC +from cpl_discord.events.on_group_remove_abc import OnGroupRemoveABC +from cpl_discord.events.on_guild_available_abc import OnGuildAvailableABC +from cpl_discord.events.on_guild_channel_create_abc import OnGuildChannelCreateABC +from cpl_discord.events.on_guild_channel_delete_abc import OnGuildChannelDeleteABC +from cpl_discord.events.on_guild_channel_pins_update_abc import OnGuildChannelPinsUpdateABC +from cpl_discord.events.on_guild_channel_update_abc import OnGuildChannelUpdateABC +from cpl_discord.events.on_guild_emojis_update_abc import OnGuildEmojisUpdateABC +from cpl_discord.events.on_guild_integrations_update_abc import OnGuildIntegrationsUpdateABC +from cpl_discord.events.on_guild_join_abc import OnGuildJoinABC +from cpl_discord.events.on_guild_remove_abc import OnGuildRemoveABC +from cpl_discord.events.on_guild_role_create_abc import OnGuildRoleCreateABC +from cpl_discord.events.on_guild_role_delete_abc import OnGuildRoleDeleteABC +from cpl_discord.events.on_guild_role_update_abc import OnGuildRoleUpdateABC +from cpl_discord.events.on_guild_unavailable_abc import OnGuildUnavailableABC +from cpl_discord.events.on_guild_update_abc import OnGuildUpdateABC +from cpl_discord.events.on_invite_create_abc import OnInviteCreateABC +from cpl_discord.events.on_invite_delete_abc import OnInviteDeleteABC +from cpl_discord.events.on_member_ban_abc import OnMemberBanABC +from cpl_discord.events.on_member_join_abc import OnMemberJoinABC +from cpl_discord.events.on_member_remove_abc import OnMemberRemoveABC +from cpl_discord.events.on_member_unban_abc import OnMemberUnbanABC +from cpl_discord.events.on_member_update_abc import OnMemberUpdateABC +from cpl_discord.events.on_message_abc import OnMessageABC +from cpl_discord.events.on_message_delete_abc import OnMessageDeleteABC +from cpl_discord.events.on_message_edit_abc import OnMessageEditABC +from cpl_discord.events.on_private_channel_create_abc import OnPrivateChannelCreateABC +from cpl_discord.events.on_private_channel_delete_abc import OnPrivateChannelDeleteABC +from cpl_discord.events.on_private_channel_pins_update_abc import OnPrivateChannelPinsUpdateABC +from cpl_discord.events.on_private_channel_update_abc import OnPrivateChannelUpdateABC +from cpl_discord.events.on_reaction_add_abc import OnReactionAddABC +from cpl_discord.events.on_reaction_clear_abc import OnReactionClearABC +from cpl_discord.events.on_reaction_clear_emoji_abc import OnReactionClearEmojiABC +from cpl_discord.events.on_reaction_remove_abc import OnReactionRemoveABC +from cpl_discord.events.on_ready_abc import OnReadyABC +from cpl_discord.events.on_relationship_add_abc import OnRelationshipAddABC +from cpl_discord.events.on_relationship_remove_abc import OnRelationshipRemoveABC +from cpl_discord.events.on_relationship_update_abc import OnRelationshipUpdateABC +from cpl_discord.events.on_resume_abc import OnResumeABC +from cpl_discord.events.on_typing_abc import OnTypingABC +from cpl_discord.events.on_user_update_abc import OnUserUpdateABC +from cpl_discord.events.on_voice_state_update_abc import OnVoiceStateUpdateABC +from cpl_discord.events.on_webhooks_update_abc import OnWebhooksUpdateABC + + +class EventTypesEnum(Enum): + on_ready = OnReadyABC + on_bulk_message_delete_abc = OnBulkMessageDeleteABC + on_connect_abc = OnConnectABC + on_disconnect_abc = OnDisconnectABC + on_group_join_abc = OnGroupJoinABC + on_group_remove_abc = OnGroupRemoveABC + on_guild_available_abc = OnGuildAvailableABC + on_guild_channel_create_abc = OnGuildChannelCreateABC + on_guild_channel_delete_abc = OnGuildChannelDeleteABC + on_guild_channel_pins_update_abc = OnGuildChannelPinsUpdateABC + on_guild_channel_update_abc = OnGuildChannelUpdateABC + on_guild_emojis_update_abc = OnGuildEmojisUpdateABC + on_guild_integrations_update_abc = OnGuildIntegrationsUpdateABC + on_guild_join_abc = OnGuildJoinABC + on_guild_remove_abc = OnGuildRemoveABC + on_guild_role_create_abc = OnGuildRoleCreateABC + on_guild_role_delete_abc = OnGuildRoleDeleteABC + on_guild_role_update_abc = OnGuildRoleUpdateABC + on_guild_unavailable_abc = OnGuildUnavailableABC + on_guild_update_abc = OnGuildUpdateABC + on_invite_create_abc = OnInviteCreateABC + on_invite_delete_abc = OnInviteDeleteABC + on_member_ban_abc = OnMemberBanABC + on_member_join_abc = OnMemberJoinABC + on_member_remove_abc = OnMemberRemoveABC + on_member_unban_abc = OnMemberUnbanABC + on_member_update_abc = OnMemberUpdateABC + on_message_abc = OnMessageABC + on_message_delete_abc = OnMessageDeleteABC + on_message_edit_abc = OnMessageEditABC + on_private_channel_create_abc = OnPrivateChannelCreateABC + on_private_channel_delete_abc = OnPrivateChannelDeleteABC + on_private_channel_pins_update_abc = OnPrivateChannelPinsUpdateABC + on_private_channel_update_abc = OnPrivateChannelUpdateABC + on_reaction_add_abc = OnReactionAddABC + on_reaction_clear_abc = OnReactionClearABC + on_reaction_clear_emoji_abc = OnReactionClearEmojiABC + on_reaction_remove_abc = OnReactionRemoveABC + on_ready_abc = OnReadyABC + on_relationship_add_abc = OnRelationshipAddABC + on_relationship_remove_abc = OnRelationshipRemoveABC + on_relationship_update_abc = OnRelationshipUpdateABC + on_resume_abc = OnResumeABC + on_typing_abc = OnTypingABC + on_user_update_abc = OnUserUpdateABC + on_voice_state_update_abc = OnVoiceStateUpdateABC + on_webhooks_update_abc = OnWebhooksUpdateABC diff --git a/src/cpl_discord/service/discord_bot_service.py b/src/cpl_discord/service/discord_bot_service.py new file mode 100644 index 00000000..00d2c767 --- /dev/null +++ b/src/cpl_discord/service/discord_bot_service.py @@ -0,0 +1,71 @@ +import sys + +import discord +from discord.ext import commands + +from cpl_core.configuration import ConfigurationABC +from cpl_core.console import Console +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.logging import LoggerABC, LoggingSettings, LoggingLevelEnum +from cpl_discord.configuration.discord_bot_settings import DiscordBotSettings +from cpl_discord.service.discord_bot_service_abc import DiscordBotServiceABC +from cpl_discord.service.discord_service_abc import DiscordServiceABC + + +class DiscordBotService(DiscordBotServiceABC): + + def __init__( + self, + config: ConfigurationABC, + logger: LoggerABC, + discord_bot_settings: DiscordBotSettings, + env: ApplicationEnvironmentABC, + logging_st: LoggingSettings, + discord_service: DiscordServiceABC + ): + # services + self._logger = logger + self._env = env + self._logging_st = logging_st + self._discord_service = discord_service + + # settings + if discord_bot_settings is None: + self._discord_settings = DiscordBotSettings() + token = config.get_configuration('TOKEN') + if token is None: + raise Exception('You have to configure discord token by appsettings or environment variables') + + prefix = config.get_configuration('PREFIX') + self._discord_settings.from_dict({ + 'Token': token, + 'Prefix': prefix if prefix is not None else '! ' + }) + else: + self._discord_settings = discord_bot_settings + + # setup super + DiscordBotServiceABC.__init__(self, command_prefix=self._discord_settings.prefix, help_command=None, intents=discord.Intents().all()) + + async def start_async(self): + self._logger.trace(__name__, 'Try to connect to discord') + await self.start(self._discord_settings.token) + # continue at on_ready + + async def stop_async(self): + self._logger.trace(__name__, 'Try to disconnect from discord') + try: + await self.close() + except Exception as e: + self._logger.error(__name__, 'Stop failed', e) + + async def on_ready(self): + self._logger.info(__name__, 'Connected to discord') + + self._logger.header(f'{self.user.name}:') + if self._logging_st.console.value >= LoggingLevelEnum.INFO.value: + Console.banner(self._env.application_name if self._env.application_name != '' else 'A bot') + + self.add_cog(self._discord_service) + + await self._discord_service.on_ready() diff --git a/src/cpl_discord/service/bot_service_abc.py b/src/cpl_discord/service/discord_bot_service_abc.py similarity index 53% rename from src/cpl_discord/service/bot_service_abc.py rename to src/cpl_discord/service/discord_bot_service_abc.py index 91f714d6..1f54f21e 100644 --- a/src/cpl_discord/service/bot_service_abc.py +++ b/src/cpl_discord/service/discord_bot_service_abc.py @@ -4,13 +4,16 @@ import discord from discord.ext import commands -class BotServiceABC(ABC, commands.Bot): +class DiscordBotServiceABC(commands.Bot): - def __init__(self): - ABC.__init__(self) + def __init__(self, **kwargs): + commands.Bot.__init__(self, **kwargs) @abstractmethod async def start_async(self): pass @abstractmethod async def stop_async(self): pass + + @abstractmethod + async def on_ready(self): pass diff --git a/src/cpl_discord/service/discord_collection.py b/src/cpl_discord/service/discord_collection.py new file mode 100644 index 00000000..a30773b9 --- /dev/null +++ b/src/cpl_discord/service/discord_collection.py @@ -0,0 +1,32 @@ +from typing import Type, Optional + +from cpl_core.console import Console +from cpl_core.dependency_injection import ServiceCollectionABC +from cpl_discord.service.discord_collection_abc import DiscordCollectionABC +from cpl_query.extension import List + +from cpl_cli import CommandABC + + +class DiscordCollection(DiscordCollectionABC): + + def __init__(self, service_collection: ServiceCollectionABC): + DiscordCollectionABC.__init__(self) + + self._services = service_collection + self._events: dict[str, List] = {} + + def add_command(self, _t: Type[CommandABC]): + self._services.add_transient(CommandABC, _t) + + def add_event(self, _t_event: Type, _t: Type): + self._services.add_transient(_t_event, _t) + if _t_event not in self._events: + self._events[_t_event] = List(type(_t_event)) + + self._events[_t_event].append(_t) + + def get_events_by_base(self, _t_event: Type) -> Optional[List]: + if _t_event not in self._events: + return None + return self._events[_t_event] diff --git a/src/cpl_discord/service/discord_collection_abc.py b/src/cpl_discord/service/discord_collection_abc.py new file mode 100644 index 00000000..5262f1a8 --- /dev/null +++ b/src/cpl_discord/service/discord_collection_abc.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod +from typing import Type + +from cpl_query.extension import List + +from cpl_cli import CommandABC + + +class DiscordCollectionABC(ABC): + + def __init__(self): + ABC.__init__(self) + + @abstractmethod + def add_command(self, _t: Type[CommandABC]): pass + + @abstractmethod + def add_event(self, _t_event: Type, _t: Type): pass + + @abstractmethod + def get_events_by_base(self, _t_event: Type): pass diff --git a/src/cpl_discord/service/discord_service.py b/src/cpl_discord/service/discord_service.py new file mode 100644 index 00000000..247ea1c2 --- /dev/null +++ b/src/cpl_discord/service/discord_service.py @@ -0,0 +1,327 @@ +from datetime import datetime +from typing import Optional, Sequence, Union, Type + +import discord +from discord.ext import commands + +from cpl_core.console import Console +from cpl_core.dependency_injection import ServiceProviderABC +from cpl_core.logging import LoggerABC +from cpl_core.utils import String +from cpl_discord.command.discord_commands_meta import DiscordCogMeta +from cpl_discord.events.on_bulk_message_delete_abc import OnBulkMessageDeleteABC +from cpl_discord.events.on_connect_abc import OnConnectABC +from cpl_discord.events.on_disconnect_abc import OnDisconnectABC +from cpl_discord.events.on_group_join_abc import OnGroupJoinABC +from cpl_discord.events.on_group_remove_abc import OnGroupRemoveABC +from cpl_discord.events.on_guild_available_abc import OnGuildAvailableABC +from cpl_discord.events.on_guild_channel_create_abc import OnGuildChannelCreateABC +from cpl_discord.events.on_guild_channel_delete_abc import OnGuildChannelDeleteABC +from cpl_discord.events.on_guild_channel_pins_update_abc import OnGuildChannelPinsUpdateABC +from cpl_discord.events.on_guild_channel_update_abc import OnGuildChannelUpdateABC +from cpl_discord.events.on_guild_emojis_update_abc import OnGuildEmojisUpdateABC +from cpl_discord.events.on_guild_integrations_update_abc import OnGuildIntegrationsUpdateABC +from cpl_discord.events.on_guild_join_abc import OnGuildJoinABC +from cpl_discord.events.on_guild_remove_abc import OnGuildRemoveABC +from cpl_discord.events.on_guild_role_create_abc import OnGuildRoleCreateABC +from cpl_discord.events.on_guild_role_delete_abc import OnGuildRoleDeleteABC +from cpl_discord.events.on_guild_role_update_abc import OnGuildRoleUpdateABC +from cpl_discord.events.on_guild_unavailable_abc import OnGuildUnavailableABC +from cpl_discord.events.on_guild_update_abc import OnGuildUpdateABC +from cpl_discord.events.on_invite_create_abc import OnInviteCreateABC +from cpl_discord.events.on_invite_delete_abc import OnInviteDeleteABC +from cpl_discord.events.on_member_ban_abc import OnMemberBanABC +from cpl_discord.events.on_member_join_abc import OnMemberJoinABC +from cpl_discord.events.on_member_remove_abc import OnMemberRemoveABC +from cpl_discord.events.on_member_unban_abc import OnMemberUnbanABC +from cpl_discord.events.on_member_update_abc import OnMemberUpdateABC +from cpl_discord.events.on_message_abc import OnMessageABC +from cpl_discord.events.on_message_delete_abc import OnMessageDeleteABC +from cpl_discord.events.on_message_edit_abc import OnMessageEditABC +from cpl_discord.events.on_private_channel_create_abc import OnPrivateChannelCreateABC +from cpl_discord.events.on_private_channel_delete_abc import OnPrivateChannelDeleteABC +from cpl_discord.events.on_private_channel_pins_update_abc import OnPrivateChannelPinsUpdateABC +from cpl_discord.events.on_private_channel_update_abc import OnPrivateChannelUpdateABC +from cpl_discord.events.on_reaction_add_abc import OnReactionAddABC +from cpl_discord.events.on_reaction_clear_abc import OnReactionClearABC +from cpl_discord.events.on_reaction_clear_emoji_abc import OnReactionClearEmojiABC +from cpl_discord.events.on_reaction_remove_abc import OnReactionRemoveABC +from cpl_discord.events.on_ready_abc import OnReadyABC +from cpl_discord.events.on_relationship_add_abc import OnRelationshipAddABC +from cpl_discord.events.on_relationship_remove_abc import OnRelationshipRemoveABC +from cpl_discord.events.on_relationship_update_abc import OnRelationshipUpdateABC +from cpl_discord.events.on_resume_abc import OnResumeABC +from cpl_discord.events.on_typing_abc import OnTypingABC +from cpl_discord.events.on_user_update_abc import OnUserUpdateABC +from cpl_discord.events.on_voice_state_update_abc import OnVoiceStateUpdateABC +from cpl_discord.events.on_webhooks_update_abc import OnWebhooksUpdateABC +from cpl_discord.service.discord_collection_abc import DiscordCollectionABC +from cpl_discord.service.discord_service_abc import DiscordServiceABC + + +class DiscordService(DiscordServiceABC, commands.Cog, metaclass=DiscordCogMeta): + + def __init__( + self, + logger: LoggerABC, + dc_collection: DiscordCollectionABC, + services: ServiceProviderABC + ): + DiscordServiceABC.__init__(self) + self._logger = logger + self._collection = dc_collection + self._services = services + + async def _handle_event(self, event: Type, *args): + event_collection = self._collection.get_events_by_base(event) + if event_collection is None: + return + + for event_type in event_collection: + event_instance = self._services.get_service(event_type) + + func_name = event.__name__ + if func_name.endswith('ABC'): + func_name = func_name.replace('ABC', '') + + func_name = String.convert_to_snake_case(func_name) + + try: + func = getattr(event_instance, func_name) + await func(*args) + except Exception as e: + self._logger.error(__name__, f'Cannot execute {func_name} of {event_instance.__name__}', e) + + @commands.Cog.listener() + async def on_connect(self): + self._logger.trace(__name__, f'Received on_connect') + await self._handle_event(OnConnectABC) + + @commands.Cog.listener() + async def on_disconnect(self): + self._logger.trace(__name__, f'Received on_disconnect') + await self._handle_event(OnDisconnectABC) + + async def on_ready(self): + self._logger.trace(__name__, f'Received on_ready') + await self._handle_event(OnReadyABC) + + @commands.Cog.listener() + async def on_resume(self): + self._logger.trace(__name__, f'Received on_resume') + await self._handle_event(OnResumeABC) + + @commands.Cog.listener() + async def on_error(self, event: str, *args, **kwargs): + self._logger.trace(__name__, f'Received on_error:\n\t{event}\n\t{args}\n\t{kwargs}') + await self._handle_event(OnReadyABC, event, *args, **kwargs) + + @commands.Cog.listener() + async def on_typing(self, channel: discord.abc.Messageable, user: Union[discord.User, discord.Member], when: datetime): + self._logger.trace(__name__, f'Received on_typing:\n\t{channel}\n\t{user}\n\t{when}') + await self._handle_event(OnTypingABC, channel, user, when) + + @commands.Cog.listener() + async def on_message(self, message: discord.Message): + self._logger.trace(__name__, f'Received on_message:\n\t{message}\n\t{message.content}') + await self._handle_event(OnMessageABC, message) + + @commands.Cog.listener() + async def on_message_delete(self, message: discord.Message): + self._logger.trace(__name__, f'Received on_message_delete:\n\t{message}\n\t{message.content}') + await self._handle_event(OnMessageDeleteABC, message) + + @commands.Cog.listener() + async def on_bulk_message_delete(self, messages: list[discord.Message]): + self._logger.trace(__name__, f'Received on_bulk_message_delete:\n\t{len(messages)}') + await self._handle_event(OnBulkMessageDeleteABC, messages) + + @commands.Cog.listener() + async def on_message_edit(self, before: discord.Message, after: discord.Message): + self._logger.trace(__name__, f'Received on_message_edit:\n\t{before}\n\t{after}') + await self._handle_event(OnMessageEditABC, before, after) + + @commands.Cog.listener() + async def on_reaction_add(self, reaction: discord.Reaction, user: discord.User): + self._logger.trace(__name__, f'Received on_reaction_add:\n\t{reaction}\n\t{user}') + await self._handle_event(OnReactionAddABC, reaction, user) + + @commands.Cog.listener() + async def on_reaction_remove(self, reaction: discord.Reaction, user: discord.User): + self._logger.trace(__name__, f'Received on_reaction_remove:\n\t{reaction}\n\t{user}') + await self._handle_event(OnReactionRemoveABC, reaction, user) + + @commands.Cog.listener() + async def on_reaction_clear(self, message: discord.Message, reactions: list[discord.Reaction]): + self._logger.trace(__name__, f'Received on_reaction_reon_reaction_clearmove:\n\t{message}\n\t{len(reactions)}') + await self._handle_event(OnReactionClearABC, message, reactions) + + @commands.Cog.listener() + async def on_reaction_clear_emoji(self, reaction: discord.Reaction): + self._logger.trace(__name__, f'Received on_reaction_clear_emoji:\n\t{reaction}') + await self._handle_event(OnReactionClearEmojiABC, reaction) + + @commands.Cog.listener() + async def on_private_channel_delete(self, channel: discord.abc.PrivateChannel): + self._logger.trace(__name__, f'Received on_private_channel_delete:\n\t{channel}') + await self._handle_event(OnPrivateChannelDeleteABC, channel) + + @commands.Cog.listener() + async def on_private_channel_create(self, channel: discord.abc.PrivateChannel): + self._logger.trace(__name__, f'Received on_private_channel_create:\n\t{channel}') + await self._handle_event(OnPrivateChannelCreateABC, channel) + + @commands.Cog.listener() + async def on_private_channel_update(self, before: discord.GroupChannel, after: discord.GroupChannel): + self._logger.trace(__name__, f'Received on_private_channel_update:\n\t{before}\n\t{after}') + await self._handle_event(OnPrivateChannelUpdateABC, before, after) + + @commands.Cog.listener() + async def on_private_channel_pins_update(self, channel: discord.abc.PrivateChannel, list_pin: Optional[datetime]): + self._logger.trace(__name__, f'Received on_private_channel_pins_update:\n\t{channel}\n\t{list_pin}') + await self._handle_event(OnPrivateChannelPinsUpdateABC, channel, list_pin) + + @commands.Cog.listener() + async def on_guild_channel_delete(self, channel: discord.abc.GuildChannel): + self._logger.trace(__name__, f'Received on_guild_channel_delete:\n\t{channel}') + await self._handle_event(OnGuildChannelDeleteABC, channel) + + @commands.Cog.listener() + async def on_guild_channel_create(self, channel: discord.abc.GuildChannel): + self._logger.trace(__name__, f'Received on_guild_channel_create:\n\t{channel}') + await self._handle_event(OnGuildChannelCreateABC, channel) + + @commands.Cog.listener() + async def on_guild_channel_update(self, before: discord.abc.GuildChannel, after: discord.abc.GuildChannel): + self._logger.trace(__name__, f'Received on_guild_channel_update:\n\t{before}\n\t{after}') + await self._handle_event(OnGuildChannelUpdateABC, before, after) + + @commands.Cog.listener() + async def on_guild_channel_pins_update(self, channel: discord.abc.GuildChannel, list_pin: Optional[datetime]): + self._logger.trace(__name__, f'Received on_guild_channel_pins_update:\n\t{channel}\n\t{list_pin}') + await self._handle_event(OnGuildChannelPinsUpdateABC, channel, list_pin) + + @commands.Cog.listener() + async def on_guild_integrations_update(self, guild: discord.Guild): + self._logger.trace(__name__, f'Received on_guild_integrations_update:\n\t{guild}') + await self._handle_event(OnGuildIntegrationsUpdateABC, guild) + + @commands.Cog.listener() + async def on_webhooks_update(self, channel: discord.abc.GuildChannel): + self._logger.trace(__name__, f'Received on_webhooks_update:\n\t{channel}') + await self._handle_event(OnWebhooksUpdateABC, channel) + + @commands.Cog.listener() + async def on_member_join(self, member: discord.Member): + self._logger.trace(__name__, f'Received on_member_join:\n\t{member}') + await self._handle_event(OnMemberJoinABC, member) + + @commands.Cog.listener() + async def on_member_remove(self, member: discord.Member): + self._logger.trace(__name__, f'Received on_member_remove:\n\t{member}') + await self._handle_event(OnMemberRemoveABC, member) + + @commands.Cog.listener() + async def on_member_update(self, before: discord.Member, after: discord.Member): + self._logger.trace(__name__, f'Received on_member_update:\n\t{before}\n\t{after}') + await self._handle_event(OnMemberUpdateABC, before, after) + + @commands.Cog.listener() + async def on_user_update(self, before: discord.User, after: discord.User): + self._logger.trace(__name__, f'Received on_user_update:\n\t{before}\n\t{after}') + await self._handle_event(OnUserUpdateABC, before, after) + + @commands.Cog.listener() + async def on_guild_join(self, guild: discord.Guild): + self._logger.trace(__name__, f'Received on_guild_join:\n\t{guild}') + await self._handle_event(OnGuildJoinABC, guild) + + @commands.Cog.listener() + async def on_guild_remove(self, guild: discord.Guild): + self._logger.trace(__name__, f'Received on_guild_remove:\n\t{guild}') + await self._handle_event(OnGuildRemoveABC, guild) + + @commands.Cog.listener() + async def on_guild_update(self, before: discord.Guild, after: discord.Guild): + self._logger.trace(__name__, f'Received on_guild_update:\n\t{before}\n\t{after}') + await self._handle_event(OnGuildUpdateABC, before, after) + + @commands.Cog.listener() + async def on_guild_role_create(self, role: discord.Role): + self._logger.trace(__name__, f'Received on_guild_role_create:\n\t{role}') + await self._handle_event(OnGuildRoleCreateABC, role) + + @commands.Cog.listener() + async def on_guild_role_delete(self, role: discord.Role): + self._logger.trace(__name__, f'Received on_guild_role_delete:\n\t{role}') + await self._handle_event(OnGuildRoleDeleteABC, role) + + @commands.Cog.listener() + async def on_guild_role_update(self, before: discord.Role, after: discord.Role): + self._logger.trace(__name__, f'Received on_guild_role_update:\n\t{before}\n\t{after}') + await self._handle_event(OnGuildRoleUpdateABC, before, after) + + @commands.Cog.listener() + async def on_guild_emojis_update(self, guild: discord.Guild, before: Sequence[discord.Emoji], after: Sequence[discord.Emoji]): + self._logger.trace(__name__, f'Received on_guild_emojis_update:\n\t{guild}\n\t{before}\n\t{after}') + await self._handle_event(OnGuildEmojisUpdateABC, guild, before, after) + + @commands.Cog.listener() + async def on_guild_available(self, guild: discord.Guild): + self._logger.trace(__name__, f'Received on_guild_available:\n\t{guild}') + await self._handle_event(OnGuildAvailableABC, guild) + + @commands.Cog.listener() + async def on_guild_unavailable(self, guild: discord.Guild): + self._logger.trace(__name__, f'Received on_guild_unavailable:\n\t{guild}') + await self._handle_event(OnGuildUnavailableABC, guild) + + @commands.Cog.listener() + async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState): + self._logger.trace(__name__, f'Received on_voice_state_update:\n\t{member}\n\t{before}\n\t{after}') + await self._handle_event(OnVoiceStateUpdateABC, member, before, after) + + @commands.Cog.listener() + async def on_member_ban(self, guild: discord.Guild, user: discord.User): + self._logger.trace(__name__, f'Received on_member_ban:\n\t{guild}\n\t{user}') + await self._handle_event(OnMemberBanABC, guild, user) + + @commands.Cog.listener() + async def on_member_unban(self, guild: discord.Guild, user: discord.User): + self._logger.trace(__name__, f'Received on_member_unban:\n\t{guild}\n\t{user}') + await self._handle_event(OnMemberUnbanABC, guild, user) + + @commands.Cog.listener() + async def on_invite_create(self, invite: discord.Invite): + self._logger.trace(__name__, f'Received on_invite_create:\n\t{invite}') + await self._handle_event(OnInviteCreateABC, invite) + + @commands.Cog.listener() + async def on_invite_delete(self, invite: discord.Invite): + self._logger.trace(__name__, f'Received on_invite_create:\n\t{invite}') + await self._handle_event(OnInviteDeleteABC, invite) + + @commands.Cog.listener() + async def on_group_join(self, channel: discord.GroupChannel, user: discord.User): + self._logger.trace(__name__, f'Received on_group_join:\n\t{channel}\n\t{user}') + await self._handle_event(OnGroupJoinABC, channel, user) + + @commands.Cog.listener() + async def on_group_remove(self, channel: discord.GroupChannel, user: discord.User): + self._logger.trace(__name__, f'Received on_group_remove:\n\t{channel}\n\t{user}') + await self._handle_event(OnGroupRemoveABC, channel, user) + + @commands.Cog.listener() + async def on_relationship_add(self, relationship: discord.Relationship): + self._logger.trace(__name__, f'Received on_relationship_add:\n\t{relationship}') + await self._handle_event(OnRelationshipAddABC, relationship) + + @commands.Cog.listener() + async def on_relationship_remove(self, relationship: discord.Relationship): + self._logger.trace(__name__, f'Received on_relationship_remove:\n\t{relationship}') + await self._handle_event(OnRelationshipRemoveABC, relationship) + + @commands.Cog.listener() + async def on_relationship_update(self, before: discord.Relationship, after: discord.Relationship): + self._logger.trace(__name__, f'Received on_relationship_update:\n\t{before}\n\t{after}') + await self._handle_event(OnRelationshipUpdateABC, before, after) diff --git a/src/cpl_discord/service/discord_service_abc.py b/src/cpl_discord/service/discord_service_abc.py new file mode 100644 index 00000000..d6cc8379 --- /dev/null +++ b/src/cpl_discord/service/discord_service_abc.py @@ -0,0 +1,152 @@ +from abc import ABC, abstractmethod +from datetime import datetime +from typing import Optional, Sequence, Union + +import discord + + +class DiscordServiceABC(ABC): + + def __init__(self): + ABC.__init__(self) + + @abstractmethod + async def on_connect(self): pass + + @abstractmethod + async def on_disconnect(self): pass + + @abstractmethod + async def on_ready(self): pass + + @abstractmethod + async def on_resume(self): pass + + @abstractmethod + async def on_error(self, event: str, *args, **kwargs): pass + + @abstractmethod + async def on_typing(self, channel: discord.abc.Messageable, user: Union[discord.User, discord.Member], when: datetime): pass + + @abstractmethod + async def on_message(self, message: discord.Message): pass + + @abstractmethod + async def on_message_delete(self, message: discord.Message): pass + + @abstractmethod + async def on_bulk_message_delete(self, messages: list[discord.Message]): pass + + @abstractmethod + async def on_message_edit(self, before: discord.Message, after: discord.Message): pass + + @abstractmethod + async def on_reaction_add(self, reaction: discord.Reaction, user: discord.User): pass + + @abstractmethod + async def on_reaction_remove(self, reaction: discord.Reaction, user: discord.User): pass + + @abstractmethod + async def on_reaction_clear(self, message: discord.Message, reactions: list[discord.Reaction]): pass + + @abstractmethod + async def on_reaction_clear_emoji(self, reaction: discord.Reaction): pass + + @abstractmethod + async def on_private_channel_delete(self, channel: discord.abc.PrivateChannel): pass + + @abstractmethod + async def on_private_channel_create(self, channel: discord.abc.PrivateChannel): pass + + @abstractmethod + async def on_private_channel_update(self, before: discord.GroupChannel, after: discord.GroupChannel): pass + + @abstractmethod + async def on_private_channel_pins_update(self, channel: discord.abc.PrivateChannel, list_pin: Optional[datetime]): pass + + @abstractmethod + async def on_guild_channel_delete(self, channel: discord.abc.GuildChannel): pass + + @abstractmethod + async def on_guild_channel_create(self, channel: discord.abc.GuildChannel): pass + + @abstractmethod + async def on_guild_channel_update(self, before: discord.abc.GuildChannel, after: discord.abc.GuildChannel): pass + + @abstractmethod + async def on_guild_channel_pins_update(self, channel: discord.abc.GuildChannel, list_pin: Optional[datetime]): pass + + @abstractmethod + async def on_guild_integrations_update(self, guild: discord.Guild): pass + + @abstractmethod + async def on_webhooks_update(self, channel: discord.abc.GuildChannel): pass + + @abstractmethod + async def on_member_join(self, member: discord.Member): pass + + @abstractmethod + async def on_member_remove(self, member: discord.Member): pass + + @abstractmethod + async def on_member_update(self, before: discord.Member, after: discord.Member): pass + + @abstractmethod + async def on_user_update(self, before: discord.User, after: discord.User): pass + + @abstractmethod + async def on_guild_join(self, guild: discord.Guild): pass + + @abstractmethod + async def on_guild_remove(self, guild: discord.Guild): pass + + @abstractmethod + async def on_guild_update(self, before: discord.Guild, after: discord.Guild): pass + + @abstractmethod + async def on_guild_role_create(self, role: discord.Role): pass + + @abstractmethod + async def on_guild_role_delete(self, role: discord.Role): pass + + @abstractmethod + async def on_guild_role_update(self, before: discord.Role, after: discord.Role): pass + + @abstractmethod + async def on_guild_emojis_update(self, guild: discord.Guild, before: Sequence[discord.Emoji], after: Sequence[discord.Emoji]): pass + + @abstractmethod + async def on_guild_available(self, guild: discord.Guild): pass + + @abstractmethod + async def on_guild_unavailable(self, guild: discord.Guild): pass + + @abstractmethod + async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState): pass + + @abstractmethod + async def on_member_ban(self, guild: discord.Guild, user: discord.User): pass + + @abstractmethod + async def on_member_unban(self, guild: discord.Guild, user: discord.User): pass + + @abstractmethod + async def on_invite_create(self, invite: discord.Invite): pass + + @abstractmethod + async def on_invite_delete(self, invite: discord.Invite): pass + + @abstractmethod + async def on_group_join(self, chhanel: discord.GroupChannel, user: discord.User): pass + + @abstractmethod + async def on_group_remove(self, chhanel: discord.GroupChannel, user: discord.User): pass + + @abstractmethod + async def on_relationship_add(self, relationship: discord.Relationship): pass + + @abstractmethod + async def on_relationship_remove(self, relationship: discord.Relationship): pass + + @abstractmethod + async def on_relationship_update(self, before: discord.Relationship, after: discord.Relationship): pass diff --git a/src/tests/custom/discord/cpl-workspace.json b/src/tests/custom/discord/cpl-workspace.json index 8db07df1..02de1c64 100644 --- a/src/tests/custom/discord/cpl-workspace.json +++ b/src/tests/custom/discord/cpl-workspace.json @@ -1,8 +1,9 @@ { "WorkspaceSettings": { - "DefaultProject": "discord", + "DefaultProject": "discord-bot", "Projects": { - "discord": "src/discord/discord.json" + "discord-bot": "src/discord_bot/discord-bot.json", + "hello-world": "src/modules/hello_world/hello-world.json" }, "Scripts": {} } diff --git a/src/tests/custom/discord/src/discord/application.py b/src/tests/custom/discord/src/discord/application.py deleted file mode 100644 index b2df0250..00000000 --- a/src/tests/custom/discord/src/discord/application.py +++ /dev/null @@ -1,16 +0,0 @@ -from cpl_core.application import ApplicationABC -from cpl_core.configuration import ConfigurationABC -from cpl_core.console import Console -from cpl_core.dependency_injection import ServiceProviderABC - - -class Application(ApplicationABC): - - def __init__(self, config: ConfigurationABC, services: ServiceProviderABC): - ApplicationABC.__init__(self, config, services) - - async def configure(self): - pass - - async def main(self): - Console.write_line('Hello World') diff --git a/src/tests/custom/discord/src/discord/startup.py b/src/tests/custom/discord/src/discord/startup.py deleted file mode 100644 index 359c03d2..00000000 --- a/src/tests/custom/discord/src/discord/startup.py +++ /dev/null @@ -1,16 +0,0 @@ -from cpl_core.application import StartupABC -from cpl_core.configuration import ConfigurationABC -from cpl_core.dependency_injection import ServiceProviderABC, ServiceCollectionABC -from cpl_core.environment import ApplicationEnvironment - - -class Startup(StartupABC): - - def __init__(self): - StartupABC.__init__(self) - - def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironment) -> ConfigurationABC: - return configuration - - def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC: - return services.build_service_provider() diff --git a/src/tests/custom/discord/src/discord/__init__.py b/src/tests/custom/discord/src/discord_bot/__init__.py similarity index 100% rename from src/tests/custom/discord/src/discord/__init__.py rename to src/tests/custom/discord/src/discord_bot/__init__.py diff --git a/src/tests/custom/discord/src/discord_bot/application.py b/src/tests/custom/discord/src/discord_bot/application.py new file mode 100644 index 00000000..4c605e75 --- /dev/null +++ b/src/tests/custom/discord/src/discord_bot/application.py @@ -0,0 +1,40 @@ +from cpl_core.application import ApplicationABC +from cpl_core.configuration import ConfigurationABC +from cpl_core.console import Console +from cpl_core.dependency_injection import ServiceProviderABC +from cpl_core.logging import LoggerABC +from cpl_discord.application.discord_bot_abc import DiscordBotApplicationABC +from cpl_discord.configuration.discord_bot_settings import DiscordBotSettings +from cpl_discord.service.discord_bot_service import DiscordBotService +from cpl_discord.service.discord_bot_service_abc import DiscordBotServiceABC + + +class Application(DiscordBotApplicationABC): + + def __init__(self, config: ConfigurationABC, services: ServiceProviderABC): + ApplicationABC.__init__(self, config, services) + + self._bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC) + self._logger: LoggerABC = services.get_service(LoggerABC) + self._bot_settings: DiscordBotSettings = config.get_configuration(DiscordBotSettings) + + async def configure(self): + pass + + async def main(self): + try: + self._logger.debug(__name__, f'Starting...\n') + self._logger.trace(__name__, f'Try to start {DiscordBotService.__name__}') + await self._bot.start_async() + except Exception as e: + self._logger.error(__name__, 'Start failed', e) + + async def stop_async(self): + try: + self._logger.trace(__name__, f'Try to stop {DiscordBotService.__name__}') + await self._bot.close() + self._logger.trace(__name__, f'Stopped {DiscordBotService.__name__}') + except Exception as e: + self._logger.error(__name__, 'stop failed', e) + + Console.write_line() diff --git a/src/tests/custom/discord/src/discord_bot/appsettings.json b/src/tests/custom/discord/src/discord_bot/appsettings.json new file mode 100644 index 00000000..2725302b --- /dev/null +++ b/src/tests/custom/discord/src/discord_bot/appsettings.json @@ -0,0 +1,14 @@ +{ + "TimeFormatSettings": { + "DateFormat": "%Y-%m-%d", + "TimeFormat": "%H:%M:%S", + "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", + "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" + }, + "LoggingSettings": { + "Path": "logs/", + "Filename": "log_dev.log", + "ConsoleLogLevel": "TRACE", + "FileLogLevel": "TRACE" + } +} \ No newline at end of file diff --git a/src/tests/custom/discord/src/discord/discord.json b/src/tests/custom/discord/src/discord_bot/discord-bot.json similarity index 97% rename from src/tests/custom/discord/src/discord/discord.json rename to src/tests/custom/discord/src/discord_bot/discord-bot.json index a3fbc95b..d91dbfcc 100644 --- a/src/tests/custom/discord/src/discord/discord.json +++ b/src/tests/custom/discord/src/discord_bot/discord-bot.json @@ -1,6 +1,6 @@ { "ProjectSettings": { - "Name": "discord", + "Name": "discord-bot", "Version": { "Major": "0", "Minor": "0", diff --git a/src/tests/custom/discord/src/discord/main.py b/src/tests/custom/discord/src/discord_bot/main.py similarity index 77% rename from src/tests/custom/discord/src/discord/main.py rename to src/tests/custom/discord/src/discord_bot/main.py index 028d4e62..909287ae 100644 --- a/src/tests/custom/discord/src/discord/main.py +++ b/src/tests/custom/discord/src/discord_bot/main.py @@ -2,8 +2,8 @@ import asyncio from cpl_core.application import ApplicationBuilder -from discord.application import Application -from discord.startup import Startup +from discord_bot.application import Application +from discord_bot.startup import Startup async def main(): diff --git a/src/tests/custom/discord/src/discord_bot/startup.py b/src/tests/custom/discord/src/discord_bot/startup.py new file mode 100644 index 00000000..8f03ab7d --- /dev/null +++ b/src/tests/custom/discord/src/discord_bot/startup.py @@ -0,0 +1,30 @@ +from cpl_core.application import StartupABC +from cpl_core.configuration import ConfigurationABC +from cpl_core.dependency_injection import ServiceProviderABC, ServiceCollectionABC +from cpl_core.environment import ApplicationEnvironment +from cpl_discord import get_discord_collection +from cpl_discord.event_types_enum import EventTypesEnum +from modules.hello_world.on_ready_event import OnReadyEvent +from modules.hello_world.on_ready_test_event import OnReadyTestEvent + + +class Startup(StartupABC): + + def __init__(self): + StartupABC.__init__(self) + + def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironment) -> ConfigurationABC: + configuration.add_json_file('appsettings.json', optional=True) + configuration.add_environment_variables('CPL_') + configuration.add_environment_variables('DISCORD_') + + return configuration + + def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC: + services.add_logging() + services.add_discord() + dc_collection = get_discord_collection(services) + dc_collection.add_event(EventTypesEnum.on_ready.value, OnReadyEvent) + dc_collection.add_event(EventTypesEnum.on_ready.value, OnReadyTestEvent) + + return services.build_service_provider() diff --git a/src/tests/custom/discord/src/modules/__init__.py b/src/tests/custom/discord/src/modules/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/tests/custom/discord/src/modules/hello_world/__init__.py b/src/tests/custom/discord/src/modules/hello_world/__init__.py new file mode 100644 index 00000000..ad5eca30 --- /dev/null +++ b/src/tests/custom/discord/src/modules/hello_world/__init__.py @@ -0,0 +1 @@ +# imports: diff --git a/src/tests/custom/discord/src/modules/hello_world/hello-world.json b/src/tests/custom/discord/src/modules/hello_world/hello-world.json new file mode 100644 index 00000000..869a7901 --- /dev/null +++ b/src/tests/custom/discord/src/modules/hello_world/hello-world.json @@ -0,0 +1,46 @@ +{ + "ProjectSettings": { + "Name": "hello-world", + "Version": { + "Major": "0", + "Minor": "0", + "Micro": "0" + }, + "Author": "", + "AuthorEmail": "", + "Description": "", + "LongDescription": "", + "URL": "", + "CopyrightDate": "", + "CopyrightName": "", + "LicenseName": "", + "LicenseDescription": "", + "Dependencies": [ + "cpl-core>=2022.7.0" + ], + "DevDependencies": [ + "cpl-cli>=2022.7.0.post1" + ], + "PythonVersion": ">=3.10.4", + "PythonPath": { + "linux": "" + }, + "Classifiers": [] + }, + "BuildSettings": { + "ProjectType": "library", + "SourcePath": "", + "OutputPath": "../../dist", + "Main": "hello_world.main", + "EntryPoint": "hello-world", + "IncludePackageData": false, + "Included": [], + "Excluded": [ + "*/__pycache__", + "*/logs", + "*/tests" + ], + "PackageData": {}, + "ProjectReferences": [] + } +} \ No newline at end of file diff --git a/src/tests/custom/discord/src/modules/hello_world/on_ready_event.py b/src/tests/custom/discord/src/modules/hello_world/on_ready_event.py new file mode 100644 index 00000000..306ccf98 --- /dev/null +++ b/src/tests/custom/discord/src/modules/hello_world/on_ready_event.py @@ -0,0 +1,12 @@ +from cpl_core.logging import LoggerABC +from cpl_discord.events.on_ready_abc import OnReadyABC + + +class OnReadyEvent(OnReadyABC): + + def __init__(self, logger: LoggerABC): + OnReadyABC.__init__(self) + self._logger = logger + + async def on_ready(self): + self._logger.info(__name__, 'Hello World') diff --git a/src/tests/custom/discord/src/modules/hello_world/on_ready_test_event.py b/src/tests/custom/discord/src/modules/hello_world/on_ready_test_event.py new file mode 100644 index 00000000..79893536 --- /dev/null +++ b/src/tests/custom/discord/src/modules/hello_world/on_ready_test_event.py @@ -0,0 +1,12 @@ +from cpl_core.logging import LoggerABC +from cpl_discord.events.on_ready_abc import OnReadyABC + + +class OnReadyTestEvent(OnReadyABC): + + def __init__(self, logger: LoggerABC): + OnReadyABC.__init__(self) + self._logger = logger + + async def on_ready(self): + self._logger.info(__name__, 'Test second on ready') diff --git a/src/tests/custom/discord/src/modules/hello_world/ping_command.py b/src/tests/custom/discord/src/modules/hello_world/ping_command.py new file mode 100644 index 00000000..0f6b8106 --- /dev/null +++ b/src/tests/custom/discord/src/modules/hello_world/ping_command.py @@ -0,0 +1,27 @@ +from discord.ext import commands +from discord.ext.commands import Context + +from cpl_core.logging import LoggerABC +from cpl_discord.command.discord_command_abc import DiscordCommandABC +from cpl_discord.service.discord_bot_service_abc import DiscordBotServiceABC + + +class PingCommand(DiscordCommandABC): + + def __init__( + self, + logger: LoggerABC, + bot: DiscordBotServiceABC, + ): + DiscordCommandABC.__init__(self) + + self._logger = logger + self._bot = bot + + self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}') + + @commands.command() + async def ping(self, ctx: Context): + self._logger.debug(__name__, f'Received command ping {ctx}') + self._logger.info(__name__, f'Bot name {self._bot.user.name}') + self._logger.trace(__name__, f'Finished ping command')