Merge pull request '0.3.1' (#187) from 0.3.1 into master

Reviewed-on: sh-edraft.de/kd_discord_bot#187
Reviewed-by: edraft-dev <dev.sven.heidemann@sh-edraft.de>
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
This commit is contained in:
Sven Heidemann 2023-01-14 10:39:27 +01:00
commit 1b5f87f869
291 changed files with 5564 additions and 3657 deletions

View File

@ -19,14 +19,16 @@
"set-version": "tools/set_version/set-version.json" "set-version": "tools/set_version/set-version.json"
}, },
"Scripts": { "Scripts": {
"format": "black ./",
"sv": "cpl set-version $ARGS", "sv": "cpl set-version $ARGS",
"set-version": "cpl run set-version $ARGS --dev; echo '';", "set-version": "cpl run set-version $ARGS --dev; echo '';",
"gv": "cpl get-version", "gv": "cpl get-version",
"get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;", "get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;",
"pre-build": "cpl set-version $ARGS", "pre-build": "cpl set-version $ARGS; black ./;",
"post-build": "cpl run post-build --dev", "post-build": "cpl run post-build --dev; black ./;",
"pre-prod": "cpl build", "pre-prod": "cpl build",
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;", "prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",

@ -1 +1 @@
Subproject commit 48c2683965611c9a96ebbb908f8dcb4d0d7d71f2 Subproject commit 6b25cc87fced30b5846505d95f20285a3e4d7adf

View File

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM python:3.10.6-alpine FROM python:3.10.4-alpine
WORKDIR /app WORKDIR /app
COPY ./dist/bot/build/kdb-bot/ . COPY ./dist/bot/build/kdb-bot/ .

2
kdb-bot/pyproject.toml Normal file
View File

@ -0,0 +1,2 @@
[tool.black]
line-length = 120

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot' __title__ = "bot"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -13,7 +13,6 @@ from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
class Application(DiscordBotApplicationABC): class Application(DiscordBotApplicationABC):
def __init__(self, config: ConfigurationABC, services: ServiceProviderABC): def __init__(self, config: ConfigurationABC, services: ServiceProviderABC):
DiscordBotApplicationABC.__init__(self, config, services) DiscordBotApplicationABC.__init__(self, config, services)
@ -42,18 +41,22 @@ class Application(DiscordBotApplicationABC):
async def main(self): async def main(self):
try: try:
self._logger.debug(__name__, f'Starting...') self._logger.debug(__name__, f"Starting...")
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module) and self._feature_flags.get_flag(FeatureFlagsEnum.api_only) and self._environment.environment_name == 'development': if (
self._feature_flags.get_flag(FeatureFlagsEnum.api_module)
and self._feature_flags.get_flag(FeatureFlagsEnum.api_only)
and self._environment.environment_name == "development"
):
self._api.start() self._api.start()
self._api.join() self._api.join()
return return
self._logger.trace(__name__, f'Try to start {DiscordBotService.__name__}') self._logger.trace(__name__, f"Try to start {DiscordBotService.__name__}")
await self._bot.start_async() await self._bot.start_async()
await self._bot.stop_async() await self._bot.stop_async()
except Exception as e: except Exception as e:
self._logger.error(__name__, 'Start failed', e) self._logger.error(__name__, "Start failed", e)
async def stop_async(self): async def stop_async(self):
if self._is_stopping: if self._is_stopping:
@ -61,13 +64,13 @@ class Application(DiscordBotApplicationABC):
self._is_stopping = True self._is_stopping = True
try: try:
self._logger.trace(__name__, f'Try to stop {DiscordBotService.__name__}') self._logger.trace(__name__, f"Try to stop {DiscordBotService.__name__}")
await self._bot.close() await self._bot.close()
self._logger.trace(__name__, f'Stopped {DiscordBotService.__name__}') self._logger.trace(__name__, f"Stopped {DiscordBotService.__name__}")
except Exception as e: except Exception as e:
self._logger.error(__name__, 'stop failed', e) self._logger.error(__name__, "stop failed", e)
Console.write_line() Console.write_line()
def is_restart(self): def is_restart(self):
return True if self._configuration.get_configuration('IS_RESTART') == 'true' else False # return True if self._configuration.get_configuration("IS_RESTART") == "true" else False #

View File

@ -4,22 +4,22 @@
"Version": { "Version": {
"Major": "0", "Major": "0",
"Minor": "3", "Minor": "3",
"Micro": "0" "Micro": "1"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de", "AuthorEmail": "sven.heidemann@sh-edraft.de",
"Description": "Keksdose bot", "Description": "Keksdose bot",
"LongDescription": "Discord bot for the Keksdose discord Server", "LongDescription": "Discord bot for the Keksdose discord Server",
"URL": "https://www.sh-edraft.de", "URL": "https://www.sh-edraft.de",
"CopyrightDate": "2022", "CopyrightDate": "2022 - 2023",
"CopyrightName": "sh-edraft.de", "CopyrightName": "sh-edraft.de",
"LicenseName": "MIT", "LicenseName": "MIT",
"LicenseDescription": "MIT, see LICENSE for more details.", "LicenseDescription": "MIT, see LICENSE for more details.",
"Dependencies": [ "Dependencies": [
"cpl-core==2022.12.0", "cpl-core==2022.12.1.post2",
"cpl-translation==2022.10.0.post2", "cpl-translation==2022.12.1",
"cpl-query==2022.12.2", "cpl-query==2022.12.2.post1",
"cpl-discord==2022.12.0", "cpl-discord==2022.12.1.post2",
"Flask==2.2.2", "Flask==2.2.2",
"Flask-Classful==0.14.2", "Flask-Classful==0.14.2",
"Flask-Cors==3.0.10", "Flask-Cors==3.0.10",
@ -31,7 +31,7 @@
"icmplib==3.0.3" "icmplib==3.0.3"
], ],
"DevDependencies": [ "DevDependencies": [
"cpl-cli==2022.12.0" "cpl-cli==2022.12.1.post2"
], ],
"PythonVersion": ">=3.10.4", "PythonVersion": ">=3.10.4",
"PythonPath": {}, "PythonPath": {},

@ -1 +1 @@
Subproject commit e6faabbd8b9fe0dbd00533ea1647e7094ea8b19e Subproject commit 54b1b3860cb570d29c8ba2590dd082a1fa744265

View File

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

View File

@ -0,0 +1,16 @@
from cpl_core.application import ApplicationExtensionABC
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.configuration.bot_settings import BotSettings
class InitBotExtension(ApplicationExtensionABC):
def __init__(self):
ApplicationExtensionABC.__init__(self)
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
settings = config.get_configuration(BotSettings)
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC, max_messages=settings.cache_max_messages)

View File

@ -6,6 +6,7 @@ from cpl_core.application import ApplicationBuilder
from cpl_core.console import Console from cpl_core.console import Console
from bot.application import Application from bot.application import Application
from bot.extension.init_bot_extension import InitBotExtension
from bot.startup import Startup from bot.startup import Startup
from bot.startup_discord_extension import StartupDiscordExtension from bot.startup_discord_extension import StartupDiscordExtension
from bot.startup_migration_extension import StartupMigrationExtension from bot.startup_migration_extension import StartupMigrationExtension
@ -18,22 +19,24 @@ from modules.database.database_extension import DatabaseExtension
class Program: class Program:
def __init__(self): def __init__(self):
self.app: Optional[Application] = None self.app: Optional[Application] = None
async def start(self): async def start(self):
# discord extension has to be loaded before modules (modules depends on discord stuff) # discord extension has to be loaded before modules (modules depends on discord stuff)
app_builder = ApplicationBuilder(Application) \ app_builder = (
.use_extension(StartupSettingsExtension) \ ApplicationBuilder(Application)
.use_extension(StartupDiscordExtension) \ .use_extension(StartupSettingsExtension)
.use_extension(StartupModuleExtension) \ .use_extension(StartupDiscordExtension)
.use_extension(StartupMigrationExtension) \ .use_extension(StartupModuleExtension)
.use_extension(BootLogExtension) \ .use_extension(StartupMigrationExtension)
.use_extension(DatabaseExtension) \ .use_extension(InitBotExtension)
.use_extension(AppApiExtension) \ .use_extension(BootLogExtension)
.use_extension(CoreExtension) \ .use_extension(DatabaseExtension)
.use_extension(AppApiExtension)
.use_extension(CoreExtension)
.use_startup(Startup) .use_startup(Startup)
)
self.app: Application = await app_builder.build_async() self.app: Application = await app_builder.build_async()
await self.app.run_async() await self.app.run_async()
@ -50,19 +53,25 @@ def main():
except KeyboardInterrupt: except KeyboardInterrupt:
asyncio.run(program.stop()) asyncio.run(program.stop())
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Cannot start the bot', f'{e} -> {traceback.format_exc()}') Console.error(
f"[ ERROR ] [ {__name__} ]: Cannot start the bot",
f"{e} -> {traceback.format_exc()}",
)
finally: finally:
try: try:
asyncio.run(program.stop()) asyncio.run(program.stop())
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Cannot stop the bot', f'{e} -> {traceback.format_exc()}') Console.error(
f"[ ERROR ] [ {__name__} ]: Cannot stop the bot",
f"{e} -> {traceback.format_exc()}",
)
if program.app is not None and program.app.is_restart(): if program.app is not None and program.app.is_restart():
del program del program
main() main()
if __name__ == '__main__': if __name__ == "__main__":
main() main()
# (( # ((

View File

@ -15,22 +15,24 @@ from modules.technician.technician_module import TechnicianModule
class ModuleList: class ModuleList:
@staticmethod @staticmethod
def get_modules(): def get_modules():
# core modules (modules out of modules folder) should be loaded first! # core modules (modules out of modules folder) should be loaded first!
return List(type, [ return List(
CoreModule, # has to be first! type,
DataModule, [
PermissionModule, CoreModule, # has to be first!
DatabaseModule, DataModule,
AutoRoleModule, PermissionModule,
BaseModule, DatabaseModule,
LevelModule, AutoRoleModule,
ApiModule, BaseModule,
StatsModule, LevelModule,
TechnicianModule, ApiModule,
# has to be last! StatsModule,
BootLogModule, TechnicianModule,
CoreExtensionModule, # has to be last!
]) BootLogModule,
CoreExtensionModule,
],
)

View File

@ -20,7 +20,6 @@ from bot_data.db_context import DBContext
class Startup(StartupABC): class Startup(StartupABC):
def __init__(self): def __init__(self):
StartupABC.__init__(self) StartupABC.__init__(self)
self._start_time = datetime.now() self._start_time = datetime.now()
@ -28,12 +27,16 @@ class Startup(StartupABC):
self._config: Optional[ConfigurationABC] = None self._config: Optional[ConfigurationABC] = None
self._feature_flags: Optional[FeatureFlagsSettings] = None self._feature_flags: Optional[FeatureFlagsSettings] = None
def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironment) -> ConfigurationABC: def configure_configuration(
self, configuration: ConfigurationABC, environment: ApplicationEnvironment
) -> ConfigurationABC:
self._config = configuration self._config = configuration
self._feature_flags = configuration.get_configuration(FeatureFlagsSettings) self._feature_flags = configuration.get_configuration(FeatureFlagsSettings)
return configuration return configuration
def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC: def configure_services(
self, services: ServiceCollectionABC, environment: ApplicationEnvironment
) -> ServiceProviderABC:
services.add_logging() services.add_logging()
if self._feature_flags.get_flag(FeatureFlagsEnum.core_module): if self._feature_flags.get_flag(FeatureFlagsEnum.core_module):
# custom logging # custom logging
@ -52,9 +55,11 @@ class Startup(StartupABC):
for c in CustomFileLoggerABC.__subclasses__(): for c in CustomFileLoggerABC.__subclasses__():
i: LoggerABC = provider.get_service(c) i: LoggerABC = provider.get_service(c)
logger: LoggerABC = provider.get_service(LoggerABC) logger: LoggerABC = provider.get_service(LoggerABC)
for flag in [f for f in FeatureFlagsEnum]: for flag in [f for f in FeatureFlagsEnum]:
logger.debug(__name__, f'Loaded feature-flag: {flag} = {self._feature_flags.get_flag(flag)}') logger.debug(
__name__,
f"Loaded feature-flag: {flag} = {self._feature_flags.get_flag(flag)}",
)
return provider return provider

View File

@ -6,7 +6,6 @@ from cpl_discord import get_discord_collection
class StartupDiscordExtension(StartupExtensionABC): class StartupDiscordExtension(StartupExtensionABC):
def __init__(self): def __init__(self):
pass pass

View File

@ -10,11 +10,13 @@ from bot_data.migration.auto_role_migration import AutoRoleMigration
from bot_data.migration.initial_migration import InitialMigration from bot_data.migration.initial_migration import InitialMigration
from bot_data.migration.level_migration import LevelMigration from bot_data.migration.level_migration import LevelMigration
from bot_data.migration.stats_migration import StatsMigration from bot_data.migration.stats_migration import StatsMigration
from bot_data.migration.user_message_count_per_hour_migration import (
UserMessageCountPerHourMigration,
)
from bot_data.service.migration_service import MigrationService from bot_data.service.migration_service import MigrationService
class StartupMigrationExtension(StartupExtensionABC): class StartupMigrationExtension(StartupExtensionABC):
def __init__(self): def __init__(self):
pass pass
@ -29,3 +31,4 @@ class StartupMigrationExtension(StartupExtensionABC):
services.add_transient(MigrationABC, LevelMigration) # 06.11.2022 #25 - 0.3.0 services.add_transient(MigrationABC, LevelMigration) # 06.11.2022 #25 - 0.3.0
services.add_transient(MigrationABC, StatsMigration) # 09.11.2022 #46 - 0.3.0 services.add_transient(MigrationABC, StatsMigration) # 09.11.2022 #46 - 0.3.0
services.add_transient(MigrationABC, AutoRoleFix1Migration) # 30.12.2022 #151 - 0.3.0 services.add_transient(MigrationABC, AutoRoleFix1Migration) # 30.12.2022 #151 - 0.3.0
services.add_transient(MigrationABC, UserMessageCountPerHourMigration) # 11.01.2023 #168 - 0.3.1

View File

@ -12,7 +12,6 @@ from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
class StartupModuleExtension(StartupExtensionABC): class StartupModuleExtension(StartupExtensionABC):
def __init__(self): def __init__(self):
self._config: Optional[ConfigurationABC] = None self._config: Optional[ConfigurationABC] = None
self._feature_flags: Optional[FeatureFlagsSettings] = None self._feature_flags: Optional[FeatureFlagsSettings] = None
@ -33,7 +32,7 @@ class StartupModuleExtension(StartupExtensionABC):
continue continue
Console.set_foreground_color(ForegroundColorEnum.green) Console.set_foreground_color(ForegroundColorEnum.green)
Console.write_line(f'[{__name__}] Loaded module: {module_type}') Console.write_line(f"[{__name__}] Loaded module: {module_type}")
Console.color_reset() Console.color_reset()
module.configure_configuration(self._config, env) module.configure_configuration(self._config, env)
module.configure_services(services, env) module.configure_services(services, env)

View File

@ -16,38 +16,45 @@ from modules.permission.configuration.permission_settings import PermissionSetti
class StartupSettingsExtension(StartupExtensionABC): class StartupSettingsExtension(StartupExtensionABC):
def __init__(self): def __init__(self):
self._start_time = datetime.now() self._start_time = datetime.now()
def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironmentABC): def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironmentABC):
# this shit has to be done here because we need settings in subsequent startup extensions # this shit has to be done here because we need settings in subsequent startup extensions
environment.set_working_directory(os.path.dirname(os.path.realpath(__file__))) environment.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
configuration.add_environment_variables('KDB_') configuration.add_environment_variables("KDB_")
configuration.add_environment_variables('DISCORD_') configuration.add_environment_variables("DISCORD_")
configuration.add_json_file(f'config/appsettings.json', optional=False) configuration.add_json_file(f"config/appsettings.json", optional=False)
configuration.add_json_file(f'config/appsettings.{environment.environment_name}.json', optional=True) configuration.add_json_file(f"config/appsettings.{environment.environment_name}.json", optional=True)
configuration.add_json_file(f'config/appsettings.{environment.host_name}.json', optional=True) configuration.add_json_file(f"config/appsettings.{environment.host_name}.json", optional=True)
# load feature-flags # load feature-flags
configuration.add_json_file(f'config/feature-flags.json', optional=False) configuration.add_json_file(f"config/feature-flags.json", optional=False)
configuration.add_json_file(f"config/feature-flags.{environment.environment_name}.json", optional=True)
configuration.add_json_file(f"config/feature-flags.{environment.host_name}.json", optional=True)
configuration.add_configuration('Startup_StartTime', str(self._start_time)) configuration.add_configuration("Startup_StartTime", str(self._start_time))
self._configure_settings_with_sub_settings(configuration, BotSettings, lambda x: x.servers, lambda x: x.id) self._configure_settings_with_sub_settings(configuration, BotSettings, lambda x: x.servers, lambda x: x.id)
self._configure_settings_with_sub_settings(configuration, BaseSettings, lambda x: x.servers, lambda x: x.id) self._configure_settings_with_sub_settings(configuration, BaseSettings, lambda x: x.servers, lambda x: x.id)
self._configure_settings_with_sub_settings(configuration, BootLogSettings, lambda x: x.servers, lambda x: x.id) self._configure_settings_with_sub_settings(configuration, BootLogSettings, lambda x: x.servers, lambda x: x.id)
self._configure_settings_with_sub_settings(configuration, LevelSettings, lambda x: x.servers, lambda x: x.id) self._configure_settings_with_sub_settings(configuration, LevelSettings, lambda x: x.servers, lambda x: x.id)
self._configure_settings_with_sub_settings(configuration, PermissionSettings, lambda x: x.servers, lambda x: x.id) self._configure_settings_with_sub_settings(
self._configure_settings_with_sub_settings(configuration, BotLoggingSettings, lambda x: x.files, lambda x: x.key) configuration, PermissionSettings, lambda x: x.servers, lambda x: x.id
)
self._configure_settings_with_sub_settings(
configuration, BotLoggingSettings, lambda x: x.files, lambda x: x.key
)
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
pass pass
@staticmethod @staticmethod
def _configure_settings_with_sub_settings(config: ConfigurationABC, settings: Type, list_atr: Callable, atr: Callable): def _configure_settings_with_sub_settings(
config: ConfigurationABC, settings: Type, list_atr: Callable, atr: Callable
):
settings: Optional[settings] = config.get_configuration(settings) settings: Optional[settings] = config.get_configuration(settings)
if settings is None: if settings is None:
return return
for sub_settings in list_atr(settings): for sub_settings in list_atr(settings):
config.add_configuration(f'{type(sub_settings).__name__}_{atr(sub_settings)}', sub_settings) config.add_configuration(f"{type(sub_settings).__name__}_{atr(sub_settings)}", sub_settings)

View File

@ -187,7 +187,13 @@
"type_error": "Der angegebene Wert ist keine Zahl! :(" "type_error": "Der angegebene Wert ist keine Zahl! :("
} }
}, },
"add": {
"xp": "Die {} von {} wurden um {} erhöht"
},
"remove": { "remove": {
"xp": "Die {} von {} wurden um {} verringert"
},
"reset": {
"xp": "Die {} von {} wurden entfernt", "xp": "Die {} von {} wurden entfernt",
"ontime": "Die {} von {} wurden entfernt" "ontime": "Die {} von {} wurden entfernt"
}, },

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api' __title__ = "bot_api"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.abc' __title__ = "bot_api.abc"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -15,78 +15,102 @@ from bot_data.model.auth_user import AuthUser
class AuthServiceABC(ABC): class AuthServiceABC(ABC):
@abstractmethod
def __init__(self):
pass
@abstractmethod @abstractmethod
def __init__(self): pass def generate_token(self, user: AuthUser) -> str:
pass
@abstractmethod @abstractmethod
def generate_token(self, user: AuthUser) -> str: pass def decode_token(self, token: str) -> dict:
pass
@abstractmethod @abstractmethod
def decode_token(self, token: str) -> dict: pass def get_decoded_token_from_request(self) -> dict:
pass
@abstractmethod @abstractmethod
def get_decoded_token_from_request(self) -> dict: pass def find_decoded_token_from_request(self) -> Optional[dict]:
pass
@abstractmethod @abstractmethod
def find_decoded_token_from_request(self) -> Optional[dict]: pass async def get_all_auth_users_async(self) -> List[AuthUserDTO]:
pass
@abstractmethod @abstractmethod
async def get_all_auth_users_async(self) -> List[AuthUserDTO]: pass async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO:
pass
@abstractmethod @abstractmethod
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO:
pass
@abstractmethod @abstractmethod
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: pass async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO:
pass
@abstractmethod @abstractmethod
async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass async def add_auth_user_async(self, user_dto: AuthUserDTO):
pass
@abstractmethod @abstractmethod
async def add_auth_user_async(self, user_dto: AuthUserDTO): pass async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
pass
@abstractmethod @abstractmethod
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): pass async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
pass
@abstractmethod @abstractmethod
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO: pass async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
pass
@abstractmethod @abstractmethod
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO):
pass
@abstractmethod @abstractmethod
async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): pass async def delete_auth_user_by_email_async(self, email: str):
pass
@abstractmethod @abstractmethod
async def delete_auth_user_by_email_async(self, email: str): pass async def delete_auth_user_async(self, user_dto: AuthUserDTO):
pass
@abstractmethod @abstractmethod
async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass async def verify_login(self, token_str: str) -> bool:
pass
@abstractmethod @abstractmethod
async def verify_login(self, token_str: str) -> bool: pass async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO:
pass
@abstractmethod @abstractmethod
async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO:
pass
@abstractmethod @abstractmethod
async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO: pass async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO:
pass
@abstractmethod @abstractmethod
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass async def revoke_async(self, token_dto: TokenDTO):
pass
@abstractmethod @abstractmethod
async def revoke_async(self, token_dto: TokenDTO): pass async def confirm_email_async(self, id: str) -> bool:
pass
@abstractmethod @abstractmethod
async def confirm_email_async(self, id: str) -> bool: pass async def forgot_password_async(self, email: str):
pass
@abstractmethod @abstractmethod
async def forgot_password_async(self, email: str): pass async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO:
pass
@abstractmethod @abstractmethod
async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: pass async def reset_password_async(self, rp_dto: ResetPasswordDTO):
pass
@abstractmethod
async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass

View File

@ -2,12 +2,14 @@ from abc import ABC, abstractmethod
class DtoABC(ABC): class DtoABC(ABC):
@abstractmethod
def __init__(self):
pass
@abstractmethod @abstractmethod
def __init__(self): pass def from_dict(self, values: dict):
pass
@abstractmethod @abstractmethod
def from_dict(self, values: dict): pass def to_dict(self) -> dict:
pass
@abstractmethod
def to_dict(self) -> dict: pass

View File

@ -2,15 +2,8 @@ from abc import ABC, abstractmethod
class SelectCriteriaABC(ABC): class SelectCriteriaABC(ABC):
@abstractmethod @abstractmethod
def __init__( def __init__(self, page_index: int, page_size: int, sort_direction: str, sort_column: str):
self,
page_index: int,
page_size: int,
sort_direction: str,
sort_column: str
):
self.page_index = page_index self.page_index = page_index
self.page_size = page_size self.page_size = page_size
self.sort_direction = sort_direction self.sort_direction = sort_direction

View File

@ -6,11 +6,12 @@ from bot_api.abc.dto_abc import DtoABC
class TransformerABC: class TransformerABC:
@staticmethod
@abstractmethod
def to_db(dto: DtoABC) -> TableABC:
pass
@staticmethod @staticmethod
@abstractmethod @abstractmethod
def to_db(dto: DtoABC) -> TableABC: pass def to_dto(db: TableABC) -> DtoABC:
pass
@staticmethod
@abstractmethod
def to_dto(db: TableABC) -> DtoABC: pass

View File

@ -25,18 +25,18 @@ from bot_api.route.route import Route
class Api(Flask): class Api(Flask):
def __init__( def __init__(
self, self,
logger: ApiLogger, logger: ApiLogger,
services: ServiceProviderABC, services: ServiceProviderABC,
api_settings: ApiSettings, api_settings: ApiSettings,
frontend_settings: FrontendSettings, frontend_settings: FrontendSettings,
auth_settings: AuthenticationSettings, auth_settings: AuthenticationSettings,
*args, **kwargs *args,
**kwargs,
): ):
if not args: if not args:
kwargs.setdefault('import_name', __name__) kwargs.setdefault("import_name", __name__)
Flask.__init__(self, *args, **kwargs) Flask.__init__(self, *args, **kwargs)
@ -56,17 +56,21 @@ class Api(Flask):
self.register_error_handler(exc_class, self.handle_exception) self.register_error_handler(exc_class, self.handle_exception)
# websockets # websockets
self._socketio = SocketIO(self, cors_allowed_origins='*', path='/api/socket.io') self._socketio = SocketIO(self, cors_allowed_origins="*", path="/api/socket.io")
self._socketio.on_event('connect', self.on_connect) self._socketio.on_event("connect", self.on_connect)
self._socketio.on_event('disconnect', self.on_disconnect) self._socketio.on_event("disconnect", self.on_disconnect)
self._requests = {} self._requests = {}
@staticmethod @staticmethod
def _get_methods_from_registered_route() -> Union[list[str], str]: def _get_methods_from_registered_route() -> Union[list[str], str]:
methods = ['Unknown'] methods = ["Unknown"]
if request.path in Route.registered_routes and len(Route.registered_routes[request.path]) >= 1 and 'methods' in Route.registered_routes[request.path][1]: if (
methods = Route.registered_routes[request.path][1]['methods'] request.path in Route.registered_routes
and len(Route.registered_routes[request.path]) >= 1
and "methods" in Route.registered_routes[request.path][1]
):
methods = Route.registered_routes[request.path][1]["methods"]
if len(methods) == 1: if len(methods) == 1:
return methods[0] return methods[0]
@ -77,7 +81,7 @@ class Api(Flask):
route = f[0] route = f[0]
kwargs = f[1] kwargs = f[1]
cls = None cls = None
qual_name_split = route.__qualname__.split('.') qual_name_split = route.__qualname__.split(".")
if len(qual_name_split) > 0: if len(qual_name_split) > 0:
cls_type = vars(sys.modules[route.__module__])[qual_name_split[0]] cls_type = vars(sys.modules[route.__module__])[qual_name_split[0]]
cls = self._services.get_service(cls_type) cls = self._services.get_service(cls_type)
@ -87,7 +91,7 @@ class Api(Flask):
self.route(path, **kwargs)(partial_f) self.route(path, **kwargs)(partial_f)
def handle_exception(self, e: Exception): def handle_exception(self, e: Exception):
self._logger.error(__name__, f'Caught error', e) self._logger.error(__name__, f"Caught error", e)
if isinstance(e, ServiceException): if isinstance(e, ServiceException):
ex: ServiceException = e ex: ServiceException = e
@ -100,7 +104,7 @@ class Api(Flask):
return jsonify(error.to_dict()), 404 return jsonify(error.to_dict()), 404
else: else:
tracking_id = uuid.uuid4() tracking_id = uuid.uuid4()
user_message = f'Tracking Id: {tracking_id}' user_message = f"Tracking Id: {tracking_id}"
self._logger.error(__name__, user_message, e) self._logger.error(__name__, user_message, e)
error = ErrorDTO(None, user_message) error = ErrorDTO(None, user_message)
return jsonify(error.to_dict()), 400 return jsonify(error.to_dict()), 400
@ -110,34 +114,42 @@ class Api(Flask):
self._requests[request] = request_id self._requests[request] = request_id
method = request.access_control_request_method method = request.access_control_request_method
self._logger.info(__name__, f'Received {request_id} @ {self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}') self._logger.info(
__name__,
f"Received {request_id} @ {self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}",
)
headers = str(request.headers).replace('\n', '\n\t\t') headers = str(request.headers).replace("\n", "\n\t\t")
data = request.get_data() data = request.get_data()
data = '' if len(data) == 0 else str(data.decode(encoding="utf-8")) data = "" if len(data) == 0 else str(data.decode(encoding="utf-8"))
text = textwrap.dedent(f'Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tUser-Agent: {request.user_agent.string}\n\tBody: {data}') text = textwrap.dedent(
f"Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tUser-Agent: {request.user_agent.string}\n\tBody: {data}"
)
self._logger.trace(__name__, text) self._logger.trace(__name__, text)
def after_request_hook(self, response: Response): def after_request_hook(self, response: Response):
method = request.access_control_request_method method = request.access_control_request_method
request_id = f'{self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}' request_id = f"{self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}"
if request in self._requests: if request in self._requests:
request_id = self._requests[request] request_id = self._requests[request]
self._logger.info(__name__, f'Answered {request_id}') self._logger.info(__name__, f"Answered {request_id}")
headers = str(request.headers).replace('\n', '\n\t\t') headers = str(request.headers).replace("\n", "\n\t\t")
data = request.get_data() data = request.get_data()
data = '' if len(data) == 0 else str(data.decode(encoding="utf-8")) data = "" if len(data) == 0 else str(data.decode(encoding="utf-8"))
text = textwrap.dedent(f'Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tResponse: {data}') text = textwrap.dedent(f"Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tResponse: {data}")
self._logger.trace(__name__, text) self._logger.trace(__name__, text)
return response return response
def start(self): def start(self):
self._logger.info(__name__, f'Starting API {self._api_settings.host}:{self._api_settings.port}') self._logger.info(
__name__,
f"Starting API {self._api_settings.host}:{self._api_settings.port}",
)
self._register_routes() self._register_routes()
self.secret_key = CredentialManager.decrypt(self._auth_settings.secret_key) self.secret_key = CredentialManager.decrypt(self._auth_settings.secret_key)
# from waitress import serve # from waitress import serve
@ -146,11 +158,11 @@ class Api(Flask):
wsgi.server( wsgi.server(
eventlet.listen((self._api_settings.host, self._api_settings.port)), eventlet.listen((self._api_settings.host, self._api_settings.port)),
self, self,
log_output=False log_output=False,
) )
def on_connect(self): def on_connect(self):
self._logger.info(__name__, f'Client connected') self._logger.info(__name__, f"Client connected")
def on_disconnect(self): def on_disconnect(self):
self._logger.info(__name__, f'Client disconnected') self._logger.info(__name__, f"Client disconnected")

View File

@ -23,16 +23,15 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
class ApiModule(ModuleABC): class ApiModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC): def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.api_module) ModuleABC.__init__(self, dc, FeatureFlagsEnum.api_module)
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
cwd = env.working_directory cwd = env.working_directory
env.set_working_directory(os.path.dirname(os.path.realpath(__file__))) env.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
config.add_json_file(f'config/apisettings.json', optional=False) config.add_json_file(f"config/apisettings.json", optional=False)
config.add_json_file(f'config/apisettings.{env.environment_name}.json', optional=True) config.add_json_file(f"config/apisettings.{env.environment_name}.json", optional=True)
config.add_json_file(f'config/apisettings.{env.host_name}.json', optional=True) config.add_json_file(f"config/apisettings.{env.host_name}.json", optional=True)
env.set_working_directory(cwd) env.set_working_directory(cwd)
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):

View File

@ -5,12 +5,7 @@ from bot_api.logging.api_logger import ApiLogger
class ApiThread(threading.Thread): class ApiThread(threading.Thread):
def __init__(self, logger: ApiLogger, api: Api):
def __init__(
self,
logger: ApiLogger,
api: Api
):
threading.Thread.__init__(self, daemon=True) threading.Thread.__init__(self, daemon=True)
self._logger = logger self._logger = logger
@ -18,7 +13,7 @@ class ApiThread(threading.Thread):
def run(self) -> None: def run(self) -> None:
try: try:
self._logger.trace(__name__, f'Try to start {type(self._api).__name__}') self._logger.trace(__name__, f"Try to start {type(self._api).__name__}")
self._api.start() self._api.start()
except Exception as e: except Exception as e:
self._logger.error(__name__, 'Start failed', e) self._logger.error(__name__, "Start failed", e)

View File

@ -11,7 +11,6 @@ from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
class AppApiExtension(ApplicationExtensionABC): class AppApiExtension(ApplicationExtensionABC):
def __init__(self): def __init__(self):
ApplicationExtensionABC.__init__(self) ApplicationExtensionABC.__init__(self)

View File

@ -4,7 +4,7 @@
"Version": { "Version": {
"Major": "0", "Major": "0",
"Minor": "3", "Minor": "3",
"Micro": "0" "Micro": "1"
}, },
"Author": "", "Author": "",
"AuthorEmail": "", "AuthorEmail": "",

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.configuration' __title__ = "bot_api.configuration"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports # imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -5,12 +5,11 @@ from cpl_core.console import Console
class ApiSettings(ConfigurationModelABC): class ApiSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._port = 80 self._port = 80
self._host = '' self._host = ""
self._redirect_to_https = False self._redirect_to_https = False
@property @property
@ -27,9 +26,9 @@ class ApiSettings(ConfigurationModelABC):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._port = int(settings['Port']) self._port = int(settings["Port"])
self._host = settings['Host'] self._host = settings["Host"]
self._redirect_to_https = bool(settings['RedirectToHTTPS']) self._redirect_to_https = bool(settings["RedirectToHTTPS"])
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -6,13 +6,12 @@ from cpl_core.console import Console
class AuthenticationSettings(ConfigurationModelABC): class AuthenticationSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._secret_key = '' self._secret_key = ""
self._issuer = '' self._issuer = ""
self._audience = '' self._audience = ""
self._token_expire_time = 0 self._token_expire_time = 0
self._refresh_token_expire_time = 0 self._refresh_token_expire_time = 0
@ -38,11 +37,11 @@ class AuthenticationSettings(ConfigurationModelABC):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._secret_key = settings['SecretKey'] self._secret_key = settings["SecretKey"]
self._issuer = settings['Issuer'] self._issuer = settings["Issuer"]
self._audience = settings['Audience'] self._audience = settings["Audience"]
self._token_expire_time = int(settings['TokenExpireTime']) self._token_expire_time = int(settings["TokenExpireTime"])
self._refresh_token_expire_time = int(settings['RefreshTokenExpireTime']) self._refresh_token_expire_time = int(settings["RefreshTokenExpireTime"])
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -6,15 +6,14 @@ from cpl_query.extension import List
class DiscordAuthenticationSettings(ConfigurationModelABC): class DiscordAuthenticationSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._client_secret = '' self._client_secret = ""
self._redirect_url = '' self._redirect_url = ""
self._scope = List() self._scope = List()
self._token_url = '' self._token_url = ""
self._auth_url = '' self._auth_url = ""
@property @property
def client_secret(self) -> str: def client_secret(self) -> str:
@ -38,11 +37,11 @@ class DiscordAuthenticationSettings(ConfigurationModelABC):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._client_secret = settings['ClientSecret'] self._client_secret = settings["ClientSecret"]
self._redirect_url = settings['RedirectURL'] self._redirect_url = settings["RedirectURL"]
self._scope = List(str, settings['Scope']) self._scope = List(str, settings["Scope"])
self._token_url = settings['TokenURL'] self._token_url = settings["TokenURL"]
self._auth_url = settings['AuthURL'] self._auth_url = settings["AuthURL"]
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -5,11 +5,10 @@ from cpl_core.console import Console
class FrontendSettings(ConfigurationModelABC): class FrontendSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._url = '' self._url = ""
@property @property
def url(self) -> str: def url(self) -> str:
@ -17,7 +16,7 @@ class FrontendSettings(ConfigurationModelABC):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._url = settings['URL'] self._url = settings["URL"]
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -5,13 +5,7 @@ from cpl_cli.configuration.version_settings_name_enum import VersionSettingsName
class VersionSettings(ConfigurationModelABC): class VersionSettings(ConfigurationModelABC):
def __init__(self, major: str = None, minor: str = None, micro: str = None):
def __init__(
self,
major: str = None,
minor: str = None,
micro: str = None
):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._major: Optional[str] = major self._major: Optional[str] = major
@ -32,15 +26,15 @@ class VersionSettings(ConfigurationModelABC):
def to_str(self) -> str: def to_str(self) -> str:
if self._micro is None: if self._micro is None:
return f'{self._major}.{self._minor}' return f"{self._major}.{self._minor}"
else: else:
return f'{self._major}.{self._minor}.{self._micro}' return f"{self._major}.{self._minor}.{self._micro}"
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
self._major = settings[VersionSettingsNameEnum.major.value] self._major = settings[VersionSettingsNameEnum.major.value]
self._minor = settings[VersionSettingsNameEnum.minor.value] self._minor = settings[VersionSettingsNameEnum.minor.value]
micro = settings[VersionSettingsNameEnum.micro.value] micro = settings[VersionSettingsNameEnum.micro.value]
if micro != '': if micro != "":
self._micro = micro self._micro = micro
def to_dict(self) -> dict: def to_dict(self) -> dict:

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.controller' __title__ = "bot_api.controller"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -20,18 +20,18 @@ from bot_data.model.auth_role_enum import AuthRoleEnum
class AuthController: class AuthController:
BasePath = '/api/auth' BasePath = "/api/auth"
def __init__( def __init__(
self, self,
config: ConfigurationABC, config: ConfigurationABC,
env: ApplicationEnvironmentABC, env: ApplicationEnvironmentABC,
logger: ApiLogger, logger: ApiLogger,
t: TranslatePipe, t: TranslatePipe,
api: Api, api: Api,
mail_settings: EMailClientSettings, mail_settings: EMailClientSettings,
mailer: EMailClientABC, mailer: EMailClientABC,
auth_service: AuthServiceABC auth_service: AuthServiceABC,
): ):
self._config = config self._config = config
self._env = env self._env = env
@ -42,55 +42,57 @@ class AuthController:
self._mailer = mailer self._mailer = mailer
self._auth_service = auth_service self._auth_service = auth_service
@Route.get(f'{BasePath}/users') @Route.get(f"{BasePath}/users")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
async def get_all_users(self) -> Response: async def get_all_users(self) -> Response:
result = await self._auth_service.get_all_auth_users_async() result = await self._auth_service.get_all_auth_users_async()
return jsonify(result.select(lambda x: x.to_dict()).to_list()) return jsonify(result.select(lambda x: x.to_dict()).to_list())
@Route.post(f'{BasePath}/users/get/filtered') @Route.post(f"{BasePath}/users/get/filtered")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
async def get_filtered_users(self) -> Response: async def get_filtered_users(self) -> Response:
dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True)) dto: AuthUserSelectCriteria = JSONProcessor.process(
AuthUserSelectCriteria, request.get_json(force=True, silent=True)
)
result = await self._auth_service.get_filtered_auth_users_async(dto) result = await self._auth_service.get_filtered_auth_users_async(dto)
result.result = result.result.select(lambda x: x.to_dict()).to_list() result.result = result.result.select(lambda x: x.to_dict()).to_list()
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.get(f'{BasePath}/users/get/<email>') @Route.get(f"{BasePath}/users/get/<email>")
@Route.authorize @Route.authorize
async def get_user_from_email(self, email: str) -> Response: async def get_user_from_email(self, email: str) -> Response:
result = await self._auth_service.get_auth_user_by_email_async(email) result = await self._auth_service.get_auth_user_by_email_async(email)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.get(f'{BasePath}/users/find/<email>') @Route.get(f"{BasePath}/users/find/<email>")
@Route.authorize @Route.authorize
async def find_user_from_email(self, email: str) -> Response: async def find_user_from_email(self, email: str) -> Response:
result = await self._auth_service.find_auth_user_by_email_async(email) result = await self._auth_service.find_auth_user_by_email_async(email)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.post(f'{BasePath}/register') @Route.post(f"{BasePath}/register")
async def register(self): async def register(self):
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.add_auth_user_async(dto) await self._auth_service.add_auth_user_async(dto)
return '', 200 return "", 200
@Route.post(f'{BasePath}/register-by-id/<id>') @Route.post(f"{BasePath}/register-by-id/<id>")
async def register_id(self, id: str): async def register_id(self, id: str):
result = await self._auth_service.confirm_email_async(id) result = await self._auth_service.confirm_email_async(id)
return jsonify(result) return jsonify(result)
@Route.post(f'{BasePath}/login') @Route.post(f"{BasePath}/login")
async def login(self) -> Response: async def login(self) -> Response:
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
result = await self._auth_service.login_async(dto) result = await self._auth_service.login_async(dto)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.get(f'{BasePath}/verify-login') @Route.get(f"{BasePath}/verify-login")
async def verify_login(self): async def verify_login(self):
token = None token = None
result = False result = False
if 'Authorization' in request.headers: if "Authorization" in request.headers:
bearer = request.headers.get('Authorization') bearer = request.headers.get("Authorization")
token = bearer.split()[1] token = bearer.split()[1]
if token is not None: if token is not None:
@ -98,58 +100,58 @@ class AuthController:
return jsonify(result) return jsonify(result)
@Route.post(f'{BasePath}/forgot-password/<email>') @Route.post(f"{BasePath}/forgot-password/<email>")
async def forgot_password(self, email: str): async def forgot_password(self, email: str):
await self._auth_service.forgot_password_async(email) await self._auth_service.forgot_password_async(email)
return '', 200 return "", 200
@Route.post(f'{BasePath}/confirm-forgot-password/<id>') @Route.post(f"{BasePath}/confirm-forgot-password/<id>")
async def confirm_forgot_password(self, id: str): async def confirm_forgot_password(self, id: str):
result = await self._auth_service.confirm_forgot_password_async(id) result = await self._auth_service.confirm_forgot_password_async(id)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.post(f'{BasePath}/reset-password') @Route.post(f"{BasePath}/reset-password")
async def reset_password(self): async def reset_password(self):
dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True)) dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True))
await self._auth_service.reset_password_async(dto) await self._auth_service.reset_password_async(dto)
return '', 200 return "", 200
@Route.post(f'{BasePath}/update-user') @Route.post(f"{BasePath}/update-user")
@Route.authorize @Route.authorize
async def update_user(self): async def update_user(self):
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.update_user_async(dto) await self._auth_service.update_user_async(dto)
return '', 200 return "", 200
@Route.post(f'{BasePath}/update-user-as-admin') @Route.post(f"{BasePath}/update-user-as-admin")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
async def update_user_as_admin(self): async def update_user_as_admin(self):
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.update_user_as_admin_async(dto) await self._auth_service.update_user_as_admin_async(dto)
return '', 200 return "", 200
@Route.post(f'{BasePath}/refresh') @Route.post(f"{BasePath}/refresh")
@Route.authorize @Route.authorize
async def refresh(self) -> Response: async def refresh(self) -> Response:
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
result = await self._auth_service.refresh_async(dto) result = await self._auth_service.refresh_async(dto)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.post(f'{BasePath}/revoke') @Route.post(f"{BasePath}/revoke")
async def revoke(self): async def revoke(self):
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
await self._auth_service.revoke_async(dto) await self._auth_service.revoke_async(dto)
return '', 200 return "", 200
@Route.post(f'{BasePath}/delete-user') @Route.post(f"{BasePath}/delete-user")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
async def delete_user(self): async def delete_user(self):
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.delete_auth_user_async(dto) await self._auth_service.delete_auth_user_async(dto)
return '', 200 return "", 200
@Route.post(f'{BasePath}/delete-user-by-mail/<email>') @Route.post(f"{BasePath}/delete-user-by-mail/<email>")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
async def delete_user_by_mail(self, email: str): async def delete_user_by_mail(self, email: str):
await self._auth_service.delete_auth_user_by_email_async(email) await self._auth_service.delete_auth_user_by_email_async(email)
return '', 200 return "", 200

View File

@ -13,7 +13,9 @@ from requests_oauthlib import OAuth2Session
from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api from bot_api.api import Api
from bot_api.configuration.discord_authentication_settings import DiscordAuthenticationSettings from bot_api.configuration.discord_authentication_settings import (
DiscordAuthenticationSettings,
)
from bot_api.json_processor import JSONProcessor from bot_api.json_processor import JSONProcessor
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.auth_user_dto import AuthUserDTO
@ -22,24 +24,24 @@ from bot_api.route.route import Route
from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_role_enum import AuthRoleEnum
# Disable SSL requirement # Disable SSL requirement
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
class AuthDiscordController: class AuthDiscordController:
BasePath = '/api/auth/discord' BasePath = "/api/auth/discord"
def __init__( def __init__(
self, self,
auth_settings: DiscordAuthenticationSettings, auth_settings: DiscordAuthenticationSettings,
config: ConfigurationABC, config: ConfigurationABC,
env: ApplicationEnvironmentABC, env: ApplicationEnvironmentABC,
logger: ApiLogger, logger: ApiLogger,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
t: TranslatePipe, t: TranslatePipe,
api: Api, api: Api,
mail_settings: EMailClientSettings, mail_settings: EMailClientSettings,
mailer: EMailClientABC, mailer: EMailClientABC,
auth_service: AuthServiceABC auth_service: AuthServiceABC,
): ):
self._auth_settings = auth_settings self._auth_settings = auth_settings
self._config = config self._config = config
@ -53,46 +55,58 @@ class AuthDiscordController:
self._auth_service = auth_service self._auth_service = auth_service
def _get_user_from_discord_response(self) -> dict: def _get_user_from_discord_response(self) -> dict:
discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=request.args.get('state'), scope=self._auth_settings.scope) discord = OAuth2Session(
self._bot.user.id,
redirect_uri=self._auth_settings.redirect_url,
state=request.args.get("state"),
scope=self._auth_settings.scope,
)
token = discord.fetch_token( token = discord.fetch_token(
self._auth_settings.token_url, self._auth_settings.token_url,
client_secret=CredentialManager.decrypt(self._auth_settings.client_secret), client_secret=CredentialManager.decrypt(self._auth_settings.client_secret),
authorization_response=request.url, authorization_response=request.url,
) )
discord = OAuth2Session(self._bot.user.id, token=token) discord = OAuth2Session(self._bot.user.id, token=token)
return discord.get('https://discordapp.com/api' + '/users/@me').json() return discord.get("https://discordapp.com/api" + "/users/@me").json()
@Route.get(f'{BasePath}/get-url') @Route.get(f"{BasePath}/get-url")
async def get_url(self): async def get_url(self):
oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope) oauth = OAuth2Session(
self._bot.user.id,
redirect_uri=self._auth_settings.redirect_url,
scope=self._auth_settings.scope,
)
login_url, state = oauth.authorization_url(self._auth_settings.auth_url) login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
return jsonify({'loginUrl': login_url}) return jsonify({"loginUrl": login_url})
@Route.get(f'{BasePath}/create-user') @Route.get(f"{BasePath}/create-user")
async def discord_create_user(self) -> Response: async def discord_create_user(self) -> Response:
response = self._get_user_from_discord_response() response = self._get_user_from_discord_response()
result = await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO( result = await self._auth_service.add_auth_user_by_discord_async(
0, AuthUserDTO(
response['username'], 0,
response['discriminator'], response["username"],
response['email'], response["discriminator"],
str(uuid.uuid4()), response["email"],
None, str(uuid.uuid4()),
AuthRoleEnum.normal None,
), response['id']) AuthRoleEnum.normal,
),
response["id"],
)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.get(f'{BasePath}/login') @Route.get(f"{BasePath}/login")
async def discord_login(self) -> Response: async def discord_login(self) -> Response:
response = self._get_user_from_discord_response() response = self._get_user_from_discord_response()
dto = AuthUserDTO( dto = AuthUserDTO(
0, 0,
response['username'], response["username"],
response['discriminator'], response["discriminator"],
response['email'], response["email"],
str(uuid.uuid4()), str(uuid.uuid4()),
None, None,
AuthRoleEnum.normal AuthRoleEnum.normal,
) )
result = await self._auth_service.login_discord_async(dto) result = await self._auth_service.login_discord_async(dto)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.controller.discord' __title__ = "bot_api.controller.discord"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -14,18 +14,18 @@ from bot_data.model.auth_role_enum import AuthRoleEnum
class ServerController: class ServerController:
BasePath = f'/api/discord/server' BasePath = f"/api/discord/server"
def __init__( def __init__(
self, self,
config: ConfigurationABC, config: ConfigurationABC,
env: ApplicationEnvironmentABC, env: ApplicationEnvironmentABC,
logger: ApiLogger, logger: ApiLogger,
t: TranslatePipe, t: TranslatePipe,
api: Api, api: Api,
mail_settings: EMailClientSettings, mail_settings: EMailClientSettings,
mailer: EMailClientABC, mailer: EMailClientABC,
discord_service: DiscordService discord_service: DiscordService,
): ):
self._config = config self._config = config
self._env = env self._env = env
@ -36,29 +36,31 @@ class ServerController:
self._mailer = mailer self._mailer = mailer
self._discord_service = discord_service self._discord_service = discord_service
@Route.get(f'{BasePath}/get/servers') @Route.get(f"{BasePath}/get/servers")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
async def get_all_servers(self) -> Response: async def get_all_servers(self) -> Response:
result = await self._discord_service.get_all_servers() result = await self._discord_service.get_all_servers()
result = result.select(lambda x: x.to_dict()).to_list() result = result.select(lambda x: x.to_dict()).to_list()
return jsonify(result) return jsonify(result)
@Route.get(f'{BasePath}/get/servers-by-user') @Route.get(f"{BasePath}/get/servers-by-user")
@Route.authorize @Route.authorize
async def get_all_servers_by_user(self) -> Response: async def get_all_servers_by_user(self) -> Response:
result = await self._discord_service.get_all_servers_by_user() result = await self._discord_service.get_all_servers_by_user()
result = result.select(lambda x: x.to_dict()).to_list() result = result.select(lambda x: x.to_dict()).to_list()
return jsonify(result) return jsonify(result)
@Route.post(f'{BasePath}/get/filtered') @Route.post(f"{BasePath}/get/filtered")
@Route.authorize @Route.authorize
async def get_filtered_servers(self) -> Response: async def get_filtered_servers(self) -> Response:
dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True)) dto: ServerSelectCriteria = JSONProcessor.process(
ServerSelectCriteria, request.get_json(force=True, silent=True)
)
result = await self._discord_service.get_filtered_servers_async(dto) result = await self._discord_service.get_filtered_servers_async(dto)
result.result = result.result.select(lambda x: x.to_dict()).to_list() result.result = result.result.select(lambda x: x.to_dict()).to_list()
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.get(f'{BasePath}/get/<id>') @Route.get(f"{BasePath}/get/<id>")
@Route.authorize @Route.authorize
async def get_server_by_id(self, id: int) -> Response: async def get_server_by_id(self, id: int) -> Response:
result = await self._discord_service.get_server_by_id_async(id).to_list() result = await self._discord_service.get_server_by_id_async(id).to_list()

View File

@ -15,18 +15,18 @@ from bot_api.route.route import Route
class GuiController: class GuiController:
BasePath = f'/api/gui' BasePath = f"/api/gui"
def __init__( def __init__(
self, self,
config: ConfigurationABC, config: ConfigurationABC,
env: ApplicationEnvironmentABC, env: ApplicationEnvironmentABC,
logger: ApiLogger, logger: ApiLogger,
t: TranslatePipe, t: TranslatePipe,
api: Api, api: Api,
mail_settings: EMailClientSettings, mail_settings: EMailClientSettings,
mailer: EMailClientABC, mailer: EMailClientABC,
auth_settings: AuthenticationSettings auth_settings: AuthenticationSettings,
): ):
self._config = config self._config = config
self._env = env self._env = env
@ -37,42 +37,48 @@ class GuiController:
self._mailer = mailer self._mailer = mailer
self._auth_settings = auth_settings self._auth_settings = auth_settings
@Route.get(f'{BasePath}/api-version') @Route.get(f"{BasePath}/api-version")
async def api_version(self): async def api_version(self):
import bot_api import bot_api
version = bot_api.version_info version = bot_api.version_info
return VersionDTO(version.major, version.minor, version.micro).to_dict() return VersionDTO(version.major, version.minor, version.micro).to_dict()
@Route.get(f'{BasePath}/settings') @Route.get(f"{BasePath}/settings")
@Route.authorize @Route.authorize
async def settings(self): async def settings(self):
import bot_api import bot_api
version = bot_api.version_info version = bot_api.version_info
return jsonify(SettingsDTO( return jsonify(
'', SettingsDTO(
VersionDTO(version.major, version.minor, version.micro), "",
os.path.abspath(os.path.join(self._env.working_directory, 'config')), VersionDTO(version.major, version.minor, version.micro),
'/', os.path.abspath(os.path.join(self._env.working_directory, "config")),
'/', "/",
self._auth_settings.token_expire_time, "/",
self._auth_settings.refresh_token_expire_time, self._auth_settings.token_expire_time,
self._mail_settings.user_name, self._auth_settings.refresh_token_expire_time,
self._mail_settings.port, self._mail_settings.user_name,
self._mail_settings.host, self._mail_settings.port,
self._mail_settings.user_name, self._mail_settings.host,
self._mail_settings.user_name, self._mail_settings.user_name,
).to_dict()) self._mail_settings.user_name,
).to_dict()
)
@Route.post(f'{BasePath}/send-test-mail/<email>') @Route.post(f"{BasePath}/send-test-mail/<email>")
@Route.authorize @Route.authorize
async def send_test_mail(self, email: str): async def send_test_mail(self, email: str):
mail = EMail() mail = EMail()
mail.add_header('Mime-Version: 1.0') mail.add_header("Mime-Version: 1.0")
mail.add_header('Content-Type: text/plain; charset=utf-8') mail.add_header("Content-Type: text/plain; charset=utf-8")
mail.add_header('Content-Transfer-Encoding: quoted-printable') mail.add_header("Content-Transfer-Encoding: quoted-printable")
mail.add_receiver(email) mail.add_receiver(email)
mail.subject = self._t.transform('api.api.test_mail.subject') mail.subject = self._t.transform("api.api.test_mail.subject")
mail.body = self._t.transform('api.api.test_mail.message').format(self._env.host_name, self._env.environment_name) mail.body = self._t.transform("api.api.test_mail.message").format(
self._env.host_name, self._env.environment_name
)
self._mailer.send_mail(mail) self._mailer.send_mail(mail)
return '', 200 return "", 200

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.event' __title__ = "bot_api.event"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -4,7 +4,6 @@ from bot_api.api_thread import ApiThread
class BotApiOnReadyEvent(OnReadyABC): class BotApiOnReadyEvent(OnReadyABC):
def __init__(self, api: ApiThread): def __init__(self, api: ApiThread):
OnReadyABC.__init__(self) OnReadyABC.__init__(self)
self._api = api self._api = api

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.exception' __title__ = "bot_api.exception"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -2,7 +2,6 @@ from bot_api.exception.service_error_code_enum import ServiceErrorCode
class ServiceException(Exception): class ServiceException(Exception):
def __init__(self, error_code: ServiceErrorCode, message: str, *args): def __init__(self, error_code: ServiceErrorCode, message: str, *args):
Exception.__init__(self, *args) Exception.__init__(self, *args)
@ -10,4 +9,4 @@ class ServiceException(Exception):
self.message = message self.message = message
def get_detailed_message(self) -> str: def get_detailed_message(self) -> str:
return f'ServiceException - ErrorCode: {self.error_code} - ErrorMessage: {self.message}' return f"ServiceException - ErrorCode: {self.error_code} - ErrorMessage: {self.message}"

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.filter' __title__ = "bot_api.filter"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -2,18 +2,16 @@ from bot_api.abc.select_criteria_abc import SelectCriteriaABC
class AuthUserSelectCriteria(SelectCriteriaABC): class AuthUserSelectCriteria(SelectCriteriaABC):
def __init__( def __init__(
self, self,
page_index: int, page_index: int,
page_size: int, page_size: int,
sort_direction: str, sort_direction: str,
sort_column: str, sort_column: str,
first_name: str,
first_name: str, last_name: str,
last_name: str, email: str,
email: str, auth_role: int,
auth_role: int
): ):
SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column) SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.filter.discord' __title__ = "bot_api.filter.discord"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -2,15 +2,13 @@ from bot_api.abc.select_criteria_abc import SelectCriteriaABC
class ServerSelectCriteria(SelectCriteriaABC): class ServerSelectCriteria(SelectCriteriaABC):
def __init__( def __init__(
self, self,
page_index: int, page_index: int,
page_size: int, page_size: int,
sort_direction: str, sort_direction: str,
sort_column: str, sort_column: str,
name: str,
name: str,
): ):
SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column) SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column)

View File

@ -5,7 +5,6 @@ from cpl_core.utils import String
class JSONProcessor: class JSONProcessor:
@staticmethod @staticmethod
def process(_t: type, values: dict) -> object: def process(_t: type, values: dict) -> object:
args = [] args = []
@ -13,14 +12,14 @@ class JSONProcessor:
sig = signature(_t.__init__) sig = signature(_t.__init__)
for param in sig.parameters.items(): for param in sig.parameters.items():
parameter = param[1] parameter = param[1]
if parameter.name == 'self' or parameter.annotation == Parameter.empty: if parameter.name == "self" or parameter.annotation == Parameter.empty:
continue continue
name = String.convert_to_camel_case(parameter.name) name = String.convert_to_camel_case(parameter.name)
name = name.replace('Dto', 'DTO') name = name.replace("Dto", "DTO")
name_first_lower = String.first_to_lower(name) name_first_lower = String.first_to_lower(name)
if name in values or name_first_lower in values: if name in values or name_first_lower in values:
value = '' value = ""
if name in values: if name in values:
value = values[name] value = values[name]
else: else:

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.logging' __title__ = "bot_api.logging"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -6,6 +6,10 @@ from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
class ApiLogger(CustomFileLoggerABC): class ApiLogger(CustomFileLoggerABC):
def __init__(
def __init__(self, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC): self,
CustomFileLoggerABC.__init__(self, 'Api', config, time_format, env) config: ConfigurationABC,
time_format: TimeFormatSettings,
env: ApplicationEnvironmentABC,
):
CustomFileLoggerABC.__init__(self, "Api", config, time_format, env)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.model' __title__ = "bot_api.model"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -5,16 +5,15 @@ from bot_data.model.auth_role_enum import AuthRoleEnum
class AuthUserDTO(DtoABC): class AuthUserDTO(DtoABC):
def __init__( def __init__(
self, self,
id: int = None, id: int = None,
first_name: str = None, first_name: str = None,
last_name: str = None, last_name: str = None,
email: str = None, email: str = None,
password: str = None, password: str = None,
confirmation_id: Optional[str] = None, confirmation_id: Optional[str] = None,
auth_role: AuthRoleEnum = None, auth_role: AuthRoleEnum = None,
): ):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -79,21 +78,21 @@ class AuthUserDTO(DtoABC):
self._auth_role = value self._auth_role = value
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._id = values['id'] self._id = values["id"]
self._first_name = values['firstName'] self._first_name = values["firstName"]
self._last_name = values['lastName'] self._last_name = values["lastName"]
self._email = values['email'] self._email = values["email"]
self._password = values['password'] self._password = values["password"]
self._is_confirmed = values['isConfirmed'] self._is_confirmed = values["isConfirmed"]
self._auth_role = AuthRoleEnum(values['authRole']) self._auth_role = AuthRoleEnum(values["authRole"])
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {
'id': self._id, "id": self._id,
'firstName': self._first_name, "firstName": self._first_name,
'lastName': self._last_name, "lastName": self._last_name,
'email': self._email, "email": self._email,
'password': self._password, "password": self._password,
'isConfirmed': self._is_confirmed, "isConfirmed": self._is_confirmed,
'authRole': self._auth_role.value, "authRole": self._auth_role.value,
} }

View File

@ -5,17 +5,13 @@ from bot_data.filtered_result import FilteredResult
class AuthUserFilteredResultDTO(DtoABC, FilteredResult): class AuthUserFilteredResultDTO(DtoABC, FilteredResult):
def __init__(self, result: List = None, total_count: int = 0): def __init__(self, result: List = None, total_count: int = 0):
DtoABC.__init__(self) DtoABC.__init__(self)
FilteredResult.__init__(self, result, total_count) FilteredResult.__init__(self, result, total_count)
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._result = values['users'] self._result = values["users"]
self._total_count = values['totalCount'] self._total_count = values["totalCount"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"users": self.result, "totalCount": self.total_count}
'users': self.result,
'totalCount': self.total_count
}

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.model.discord' __title__ = "bot_api.model.discord"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -4,15 +4,13 @@ from bot_api.abc.dto_abc import DtoABC
class ServerDTO(DtoABC): class ServerDTO(DtoABC):
def __init__( def __init__(
self, self,
server_id: int, server_id: int,
discord_id: int, discord_id: int,
name: str, name: str,
member_count: int, member_count: int,
icon_url: Optional[str] icon_url: Optional[str],
): ):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -21,19 +19,19 @@ class ServerDTO(DtoABC):
self._name = name self._name = name
self._member_count = member_count self._member_count = member_count
self._icon_url = icon_url self._icon_url = icon_url
@property @property
def server_id(self) -> int: def server_id(self) -> int:
return self._server_id return self._server_id
@property @property
def discord_id(self) -> int: def discord_id(self) -> int:
return self._discord_id return self._discord_id
@property @property
def name(self) -> str: def name(self) -> str:
return self._name return self._name
@property @property
def member_count(self) -> int: def member_count(self) -> int:
return self._member_count return self._member_count
@ -43,16 +41,16 @@ class ServerDTO(DtoABC):
return self._icon_url return self._icon_url
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._server_id = int(values['serverId']) self._server_id = int(values["serverId"])
self._discord_id = int(values['discordId']) self._discord_id = int(values["discordId"])
self._name = values['name'] self._name = values["name"]
self._icon_url = values['iconURL'] self._icon_url = values["iconURL"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {
'serverId': self._server_id, "serverId": self._server_id,
'discordId': self._discord_id, "discordId": self._discord_id,
'name': self._name, "name": self._name,
'memberCount': self._member_count, "memberCount": self._member_count,
'iconURL': self._icon_url, "iconURL": self._icon_url,
} }

View File

@ -5,17 +5,13 @@ from bot_data.filtered_result import FilteredResult
class ServerFilteredResultDTO(DtoABC, FilteredResult): class ServerFilteredResultDTO(DtoABC, FilteredResult):
def __init__(self, result: List = None, total_count: int = 0): def __init__(self, result: List = None, total_count: int = 0):
DtoABC.__init__(self) DtoABC.__init__(self)
FilteredResult.__init__(self, result, total_count) FilteredResult.__init__(self, result, total_count)
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._result = values['servers'] self._result = values["servers"]
self._total_count = values['totalCount'] self._total_count = values["totalCount"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"servers": self.result, "totalCount": self.total_count}
'servers': self.result,
'totalCount': self.total_count
}

View File

@ -6,16 +6,13 @@ from bot_api.abc.dto_abc import DtoABC
class EMailStringDTO(DtoABC): class EMailStringDTO(DtoABC):
def __init__(self, email: str): def __init__(self, email: str):
DtoABC.__init__(self) DtoABC.__init__(self)
self._email = email self._email = email
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._email = values['email'] self._email = values["email"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"email": self._email}
'email': self._email
}

View File

@ -8,7 +8,6 @@ from bot_api.exception.service_error_code_enum import ServiceErrorCode
class ErrorDTO(DtoABC): class ErrorDTO(DtoABC):
def __init__(self, error_code: Optional[ServiceErrorCode], message: str): def __init__(self, error_code: Optional[ServiceErrorCode], message: str):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -24,11 +23,8 @@ class ErrorDTO(DtoABC):
return self._message return self._message
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._error_code = values['ErrorCode'] self._error_code = values["ErrorCode"]
self._message = values['Message'] self._message = values["Message"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"errorCode": int(self._error_code.value), "message": self._message}
'errorCode': int(self._error_code.value),
'message': self._message
}

View File

@ -6,11 +6,10 @@ from bot_data.model.auth_role_enum import AuthRoleEnum
class OAuthDTO(DtoABC): class OAuthDTO(DtoABC):
def __init__( def __init__(
self, self,
user: AuthUserDTO, user: AuthUserDTO,
o_auth_id: Optional[str], o_auth_id: Optional[str],
): ):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -34,11 +33,8 @@ class OAuthDTO(DtoABC):
self._oauth_id = value self._oauth_id = value
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._user = AuthUserDTO().from_dict(values['user']) self._user = AuthUserDTO().from_dict(values["user"])
self._oauth_id = values['oAuthId'] self._oauth_id = values["oAuthId"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"user": self._user.to_dict(), "oAuthId": self._oauth_id}
'user': self._user.to_dict(),
'oAuthId': self._oauth_id
}

View File

@ -6,7 +6,6 @@ from bot_api.abc.dto_abc import DtoABC
class ResetPasswordDTO(DtoABC): class ResetPasswordDTO(DtoABC):
def __init__(self, id: str, password: str): def __init__(self, id: str, password: str):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -22,11 +21,8 @@ class ResetPasswordDTO(DtoABC):
return self._password return self._password
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._id = values['id'] self._id = values["id"]
self._password = values['password'] self._password = values["password"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"id": self._id, "password": self._password}
'id': self._id,
'password': self._password
}

View File

@ -3,21 +3,20 @@ from bot_api.model.version_dto import VersionDTO
class SettingsDTO(DtoABC): class SettingsDTO(DtoABC):
def __init__( def __init__(
self, self,
web_version: str, web_version: str,
api_version: VersionDTO, api_version: VersionDTO,
config_path: str, config_path: str,
web_base_url: str, web_base_url: str,
api_base_url: str, api_base_url: str,
token_expire_time: int, token_expire_time: int,
refresh_token_expire_time: int, refresh_token_expire_time: int,
mail_user: str, mail_user: str,
mail_port: int, mail_port: int,
mail_host: str, mail_host: str,
mail_transceiver: str, mail_transceiver: str,
mail_transceiver_address: str, mail_transceiver_address: str,
): ):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -37,31 +36,31 @@ class SettingsDTO(DtoABC):
self._mail_transceiver_address = mail_transceiver_address self._mail_transceiver_address = mail_transceiver_address
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._web_version = values['webVersion'] self._web_version = values["webVersion"]
self._api_version.from_dict(values['apiVersion']) self._api_version.from_dict(values["apiVersion"])
self._config_path = values['configPath'] self._config_path = values["configPath"]
self._web_base_url = values['webBaseURL'] self._web_base_url = values["webBaseURL"]
self._api_base_url = values['apiBaseURL'] self._api_base_url = values["apiBaseURL"]
self._token_expire_time = values['tokenExpireTime'] self._token_expire_time = values["tokenExpireTime"]
self._refresh_token_expire_time = values['refreshTokenExpireTime'] self._refresh_token_expire_time = values["refreshTokenExpireTime"]
self._mail_user = values['mailUser'] self._mail_user = values["mailUser"]
self._mail_port = values['mailPort'] self._mail_port = values["mailPort"]
self._mail_host = values['mailHost'] self._mail_host = values["mailHost"]
self._mail_transceiver = values['mailTransceiver'] self._mail_transceiver = values["mailTransceiver"]
self._mail_transceiver_address = values['mailTransceiverAddress'] self._mail_transceiver_address = values["mailTransceiverAddress"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {
'webVersion': self._web_version, "webVersion": self._web_version,
'apiVersion': self._api_version.str, "apiVersion": self._api_version.str,
'configPath': self._config_path, "configPath": self._config_path,
'webBaseURL': self._web_base_url, "webBaseURL": self._web_base_url,
'apiBaseURL': self._api_base_url, "apiBaseURL": self._api_base_url,
'tokenExpireTime': self._token_expire_time, "tokenExpireTime": self._token_expire_time,
'refreshTokenExpireTime': self._refresh_token_expire_time, "refreshTokenExpireTime": self._refresh_token_expire_time,
'mailUser': self._mail_user, "mailUser": self._mail_user,
'mailPort': self._mail_port, "mailPort": self._mail_port,
'mailHost': self._mail_host, "mailHost": self._mail_host,
'mailTransceiver': self._mail_transceiver, "mailTransceiver": self._mail_transceiver,
'mailTransceiverAddress': self._mail_transceiver_address, "mailTransceiverAddress": self._mail_transceiver_address,
} }

View File

@ -6,27 +6,23 @@ from bot_api.abc.dto_abc import DtoABC
class TokenDTO(DtoABC): class TokenDTO(DtoABC):
def __init__(self, token: str, refresh_token: str): def __init__(self, token: str, refresh_token: str):
DtoABC.__init__(self) DtoABC.__init__(self)
self._token = token self._token = token
self._refresh_token = refresh_token self._refresh_token = refresh_token
@property @property
def token(self) -> str: def token(self) -> str:
return self._token return self._token
@property @property
def refresh_token(self) -> str: def refresh_token(self) -> str:
return self._refresh_token return self._refresh_token
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._token = values['token'] self._token = values["token"]
self._refresh_token = values['refreshToken'] self._refresh_token = values["refreshToken"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"token": self._token, "refreshToken": self._refresh_token}
'token': self._token,
'refreshToken': self._refresh_token
}

View File

@ -7,12 +7,11 @@ from bot_api.model.auth_user_dto import AuthUserDTO
class UpdateAuthUserDTO(DtoABC): class UpdateAuthUserDTO(DtoABC):
def __init__( def __init__(
self, self,
auth_user_dto: AuthUserDTO, auth_user_dto: AuthUserDTO,
new_auth_user_dto: AuthUserDTO, new_auth_user_dto: AuthUserDTO,
change_password: bool = False change_password: bool = False,
): ):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -33,13 +32,13 @@ class UpdateAuthUserDTO(DtoABC):
return self._change_password return self._change_password
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._auth_user = AuthUserDTO().from_dict(values['authUser']) self._auth_user = AuthUserDTO().from_dict(values["authUser"])
self._new_auth_user = AuthUserDTO().from_dict(values['newAuthUser']) self._new_auth_user = AuthUserDTO().from_dict(values["newAuthUser"])
self._change_password = False if 'changePassword' not in values else bool(values['changePassword']) self._change_password = False if "changePassword" not in values else bool(values["changePassword"])
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {
'authUser': self._auth_user, "authUser": self._auth_user,
'newAuthUser': self._new_auth_user, "newAuthUser": self._new_auth_user,
'changePassword': self._change_password "changePassword": self._change_password,
} }

View File

@ -6,7 +6,6 @@ from bot_api.abc.dto_abc import DtoABC
class VersionDTO(DtoABC): class VersionDTO(DtoABC):
def __init__(self, major: str = None, minor: str = None, micro: str = None): def __init__(self, major: str = None, minor: str = None, micro: str = None):
DtoABC.__init__(self) DtoABC.__init__(self)
@ -28,16 +27,16 @@ class VersionDTO(DtoABC):
@property @property
def str(self) -> str: def str(self) -> str:
return f'{self._major}.{self._minor}.{self._micro}' return f"{self._major}.{self._minor}.{self._micro}"
def from_dict(self, values: dict): def from_dict(self, values: dict):
self._major = values['major'] self._major = values["major"]
self._minor = values['minor'] self._minor = values["minor"]
self._micro = values['micro'] self._micro = values["micro"]
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {
'major': self._major, "major": self._major,
'minor': self._minor, "minor": self._minor,
'micro': self._micro, "micro": self._micro,
} }

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.route' __title__ = "bot_api.route"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -32,39 +32,39 @@ class Route:
@wraps(f) @wraps(f)
async def decorator(*args, **kwargs): async def decorator(*args, **kwargs):
token = None token = None
if 'Authorization' in request.headers: if "Authorization" in request.headers:
bearer = request.headers.get('Authorization') bearer = request.headers.get("Authorization")
token = bearer.split()[1] token = bearer.split()[1]
if token is None: if token is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token not set') ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token not set")
error = ErrorDTO(ex.error_code, ex.message) error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401 return jsonify(error.to_dict()), 401
if cls._auth_users is None or cls._auth is None: if cls._auth_users is None or cls._auth is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Authorize is not initialized') ex = ServiceException(ServiceErrorCode.Unauthorized, f"Authorize is not initialized")
error = ErrorDTO(ex.error_code, ex.message) error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401 return jsonify(error.to_dict()), 401
if not cls._auth.verify_login(token): if not cls._auth.verify_login(token):
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token expired') ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token expired")
error = ErrorDTO(ex.error_code, ex.message) error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401 return jsonify(error.to_dict()), 401
token = cls._auth.decode_token(token) token = cls._auth.decode_token(token)
if token is None or 'email' not in token: if token is None or "email" not in token:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid') ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token invalid")
error = ErrorDTO(ex.error_code, ex.message) error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401 return jsonify(error.to_dict()), 401
user = cls._auth_users.get_auth_user_by_email(token['email']) user = cls._auth_users.get_auth_user_by_email(token["email"])
if user is None: if user is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid') ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token invalid")
error = ErrorDTO(ex.error_code, ex.message) error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401 return jsonify(error.to_dict()), 401
if role is not None and user.auth_role.value < role.value: if role is not None and user.auth_role.value < role.value:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Role {role} required') ex = ServiceException(ServiceErrorCode.Unauthorized, f"Role {role} required")
error = ErrorDTO(ex.error_code, ex.message) error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 403 return jsonify(error.to_dict()), 403
@ -84,20 +84,20 @@ class Route:
@classmethod @classmethod
def get(cls, path=None, **kwargs): def get(cls, path=None, **kwargs):
return cls.route(path, methods=['GET'], **kwargs) return cls.route(path, methods=["GET"], **kwargs)
@classmethod @classmethod
def post(cls, path=None, **kwargs): def post(cls, path=None, **kwargs):
return cls.route(path, methods=['POST'], **kwargs) return cls.route(path, methods=["POST"], **kwargs)
@classmethod @classmethod
def head(cls, path=None, **kwargs): def head(cls, path=None, **kwargs):
return cls.route(path, methods=['HEAD'], **kwargs) return cls.route(path, methods=["HEAD"], **kwargs)
@classmethod @classmethod
def put(cls, path=None, **kwargs): def put(cls, path=None, **kwargs):
return cls.route(path, methods=['PUT'], **kwargs) return cls.route(path, methods=["PUT"], **kwargs)
@classmethod @classmethod
def delete(cls, path=None, **kwargs): def delete(cls, path=None, **kwargs):
return cls.route(path, methods=['DELETE'], **kwargs) return cls.route(path, methods=["DELETE"], **kwargs)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.service' __title__ = "bot_api.service"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports # imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -38,26 +38,24 @@ from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.auth_user import AuthUser from bot_data.model.auth_user import AuthUser
from bot_data.model.auth_user_users_relation import AuthUserUsersRelation from bot_data.model.auth_user_users_relation import AuthUserUsersRelation
_email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' _email_regex = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"
class AuthService(AuthServiceABC): class AuthService(AuthServiceABC):
def __init__( def __init__(
self, self,
env: ApplicationEnvironmentABC, env: ApplicationEnvironmentABC,
logger: ApiLogger, logger: ApiLogger,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
db: DatabaseContextABC, db: DatabaseContextABC,
auth_users: AuthUserRepositoryABC, auth_users: AuthUserRepositoryABC,
users: UserRepositoryABC, users: UserRepositoryABC,
servers: ServerRepositoryABC, servers: ServerRepositoryABC,
# mailer: MailThread, # mailer: MailThread,
mailer: EMailClientABC, mailer: EMailClientABC,
t: TranslatePipe, t: TranslatePipe,
auth_settings: AuthenticationSettings, auth_settings: AuthenticationSettings,
frontend_settings: FrontendSettings, frontend_settings: FrontendSettings,
): ):
AuthServiceABC.__init__(self) AuthServiceABC.__init__(self)
@ -75,7 +73,7 @@ class AuthService(AuthServiceABC):
@staticmethod @staticmethod
def _hash_sha256(password: str, salt: str) -> str: def _hash_sha256(password: str, salt: str) -> str:
return hashlib.sha256(f'{password}{salt}'.encode('utf-8')).hexdigest() return hashlib.sha256(f"{password}{salt}".encode("utf-8")).hexdigest()
@staticmethod @staticmethod
def _is_email_valid(email: str) -> bool: def _is_email_valid(email: str) -> bool:
@ -87,14 +85,14 @@ class AuthService(AuthServiceABC):
def generate_token(self, user: AuthUser) -> str: def generate_token(self, user: AuthUser) -> str:
token = jwt.encode( token = jwt.encode(
payload={ payload={
'user_id': user.id, "user_id": user.id,
'email': user.email, "email": user.email,
'role': user.auth_role.value, "role": user.auth_role.value,
'exp': datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.token_expire_time), "exp": datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.token_expire_time),
'iss': self._auth_settings.issuer, "iss": self._auth_settings.issuer,
'aud': self._auth_settings.audience "aud": self._auth_settings.audience,
}, },
key=CredentialManager.decrypt(self._auth_settings.secret_key) key=CredentialManager.decrypt(self._auth_settings.secret_key),
) )
return token return token
@ -105,39 +103,43 @@ class AuthService(AuthServiceABC):
key=CredentialManager.decrypt(self._auth_settings.secret_key), key=CredentialManager.decrypt(self._auth_settings.secret_key),
issuer=self._auth_settings.issuer, issuer=self._auth_settings.issuer,
audience=self._auth_settings.audience, audience=self._auth_settings.audience,
algorithms=['HS256'] algorithms=["HS256"],
) )
def get_decoded_token_from_request(self) -> dict: def get_decoded_token_from_request(self) -> dict:
token = None token = None
if 'Authorization' in request.headers: if "Authorization" in request.headers:
bearer = request.headers.get('Authorization') bearer = request.headers.get("Authorization")
token = bearer.split()[1] token = bearer.split()[1]
if token is None: if token is None:
raise ServiceException(ServiceErrorCode.Unauthorized, f'Token not set') raise ServiceException(ServiceErrorCode.Unauthorized, f"Token not set")
return jwt.decode( return jwt.decode(
token, token,
key=CredentialManager.decrypt(self._auth_settings.secret_key), key=CredentialManager.decrypt(self._auth_settings.secret_key),
issuer=self._auth_settings.issuer, issuer=self._auth_settings.issuer,
audience=self._auth_settings.audience, audience=self._auth_settings.audience,
algorithms=['HS256'] algorithms=["HS256"],
) )
def find_decoded_token_from_request(self) -> Optional[dict]: def find_decoded_token_from_request(self) -> Optional[dict]:
token = None token = None
if 'Authorization' in request.headers: if "Authorization" in request.headers:
bearer = request.headers.get('Authorization') bearer = request.headers.get("Authorization")
token = bearer.split()[1] token = bearer.split()[1]
return jwt.decode( return (
token, jwt.decode(
key=CredentialManager.decrypt(self._auth_settings.secret_key), token,
issuer=self._auth_settings.issuer, key=CredentialManager.decrypt(self._auth_settings.secret_key),
audience=self._auth_settings.audience, issuer=self._auth_settings.issuer,
algorithms=['HS256'] audience=self._auth_settings.audience,
) if token is not None else None algorithms=["HS256"],
)
if token is not None
else None
)
def _create_and_save_refresh_token(self, user: AuthUser) -> str: def _create_and_save_refresh_token(self, user: AuthUser) -> str:
token = str(uuid.uuid4()) token = str(uuid.uuid4())
@ -149,58 +151,56 @@ class AuthService(AuthServiceABC):
def _send_link_mail(self, email: str, subject: str, message: str): def _send_link_mail(self, email: str, subject: str, message: str):
url = self._frontend_settings.url url = self._frontend_settings.url
if not url.endswith('/'): if not url.endswith("/"):
url = f'{url}/' url = f"{url}/"
self._mailer.connect() self._mailer.connect()
mail = EMail() mail = EMail()
mail.add_header('Mime-Version: 1.0') mail.add_header("Mime-Version: 1.0")
mail.add_header('Content-Type: text/plain; charset=utf-8') mail.add_header("Content-Type: text/plain; charset=utf-8")
mail.add_header('Content-Transfer-Encoding: quoted-printable') mail.add_header("Content-Transfer-Encoding: quoted-printable")
mail.add_receiver(str(email)) mail.add_receiver(str(email))
mail.subject = subject mail.subject = subject
mail.body = textwrap.dedent(f"""{message} mail.body = textwrap.dedent(
f"""{message}
{self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)} {self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)}
""") """
)
thr = Thread(target=self._mailer.send_mail, args=[mail]) thr = Thread(target=self._mailer.send_mail, args=[mail])
thr.start() thr.start()
def _send_confirmation_id_to_user(self, user: AuthUser): def _send_confirmation_id_to_user(self, user: AuthUser):
url = self._frontend_settings.url url = self._frontend_settings.url
if not url.endswith('/'): if not url.endswith("/"):
url = f'{url}/' url = f"{url}/"
self._send_link_mail( self._send_link_mail(
user.email, user.email,
self._t.transform('api.auth.confirmation.subject').format(user.first_name, user.last_name), self._t.transform("api.auth.confirmation.subject").format(user.first_name, user.last_name),
self._t.transform('api.auth.confirmation.message').format(url, user.confirmation_id) self._t.transform("api.auth.confirmation.message").format(url, user.confirmation_id),
) )
def _send_forgot_password_id_to_user(self, user: AuthUser): def _send_forgot_password_id_to_user(self, user: AuthUser):
url = self._frontend_settings.url url = self._frontend_settings.url
if not url.endswith('/'): if not url.endswith("/"):
url = f'{url}/' url = f"{url}/"
self._send_link_mail( self._send_link_mail(
user.email, user.email,
self._t.transform('api.auth.forgot_password.subject').format(user.first_name, user.last_name), self._t.transform("api.auth.forgot_password.subject").format(user.first_name, user.last_name),
self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id) self._t.transform("api.auth.forgot_password.message").format(url, user.forgot_password_id),
) )
async def get_all_auth_users_async(self) -> List[AuthUserDTO]: async def get_all_auth_users_async(self) -> List[AuthUserDTO]:
result = self._auth_users.get_all_auth_users() \ result = self._auth_users.get_all_auth_users().select(lambda x: AUT.to_dto(x))
.select(lambda x: AUT.to_dto(x))
return List(AuthUserDTO, result) return List(AuthUserDTO, result)
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO:
users = self._auth_users.get_filtered_auth_users(criteria) users = self._auth_users.get_filtered_auth_users(criteria)
result = users.result.select(lambda x: AUT.to_dto(x)) result = users.result.select(lambda x: AUT.to_dto(x))
return AuthUserFilteredResultDTO( return AuthUserFilteredResultDTO(List(AuthUserDTO, result), users.total_count)
List(AuthUserDTO, result),
users.total_count
)
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO:
try: try:
@ -208,8 +208,8 @@ class AuthService(AuthServiceABC):
user = self._auth_users.get_auth_user_by_email(email) user = self._auth_users.get_auth_user_by_email(email)
return AUT.to_dto(user, password=user.password if with_password else None) return AUT.to_dto(user, password=user.password if with_password else None)
except Exception as e: except Exception as e:
self._logger.error(__name__, f'AuthUser not found', e) self._logger.error(__name__, f"AuthUser not found", e)
raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}') raise ServiceException(ServiceErrorCode.InvalidData, f"User not found {email}")
async def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: async def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]:
user = self._auth_users.find_auth_user_by_email(email) user = self._auth_users.find_auth_user_by_email(email)
@ -218,7 +218,7 @@ class AuthService(AuthServiceABC):
async def add_auth_user_async(self, user_dto: AuthUserDTO): async def add_auth_user_async(self, user_dto: AuthUserDTO):
db_user = self._auth_users.find_auth_user_by_email(user_dto.email) db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is not None: if db_user is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') raise ServiceException(ServiceErrorCode.InvalidUser, "User already exists")
user = AUT.to_db(user_dto) user = AUT.to_db(user_dto)
if self._auth_users.get_all_auth_users().count() == 0: if self._auth_users.get_all_auth_users().count() == 0:
@ -227,26 +227,26 @@ class AuthService(AuthServiceABC):
user.password_salt = uuid.uuid4() user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(user_dto.password, user.password_salt) user.password = self._hash_sha256(user_dto.password, user.password_salt)
if not self._is_email_valid(user.email): if not self._is_email_valid(user.email):
raise ServiceException(ServiceErrorCode.InvalidData, 'Invalid E-Mail address') raise ServiceException(ServiceErrorCode.InvalidData, "Invalid E-Mail address")
try: try:
user.confirmation_id = uuid.uuid4() user.confirmation_id = uuid.uuid4()
self._auth_users.add_auth_user(user) self._auth_users.add_auth_user(user)
self._send_confirmation_id_to_user(user) self._send_confirmation_id_to_user(user)
self._db.save_changes() self._db.save_changes()
self._logger.info(__name__, f'Added auth user with E-Mail: {user_dto.email}') self._logger.info(__name__, f"Added auth user with E-Mail: {user_dto.email}")
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Cannot add user with E-Mail {user_dto.email}', e) self._logger.error(__name__, f"Cannot add user with E-Mail {user_dto.email}", e)
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail") raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
db_user = self._auth_users.find_auth_user_by_email(dto.user.email) db_user = self._auth_users.find_auth_user_by_email(dto.user.email)
if db_user is None: if db_user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') raise ServiceException(ServiceErrorCode.InvalidUser, "User not found")
if db_user.oauth_id != dto.oauth_id: if db_user.oauth_id != dto.oauth_id:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong OAuthId') raise ServiceException(ServiceErrorCode.InvalidUser, "Wrong OAuthId")
try: try:
db_user.first_name = dto.user.first_name db_user.first_name = dto.user.first_name
@ -257,9 +257,9 @@ class AuthService(AuthServiceABC):
db_user.confirmation_id = uuid.uuid4() db_user.confirmation_id = uuid.uuid4()
self._send_confirmation_id_to_user(db_user) self._send_confirmation_id_to_user(db_user)
self._auth_users.update_auth_user(db_user) self._auth_users.update_auth_user(db_user)
self._logger.info(__name__, f'Added auth user with E-Mail: {dto.user.email}') self._logger.info(__name__, f"Added auth user with E-Mail: {dto.user.email}")
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Cannot add user with E-Mail {dto.user.email}', e) self._logger.error(__name__, f"Cannot add user with E-Mail {dto.user.email}", e)
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail") raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
self._db.save_changes() self._db.save_changes()
@ -270,23 +270,23 @@ class AuthService(AuthServiceABC):
# user exists # user exists
if db_auth_user is not None and db_auth_user.users.count() > 0: if db_auth_user is not None and db_auth_user.users.count() > 0:
# raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') # raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
self._logger.debug(__name__, f'Discord user already exists') self._logger.debug(__name__, f"Discord user already exists")
return OAuthDTO(AUT.to_dto(db_auth_user), None) return OAuthDTO(AUT.to_dto(db_auth_user), None)
# user exists but discord user id not set # user exists but discord user id not set
elif db_auth_user is not None and db_auth_user.users.count() == 0: elif db_auth_user is not None and db_auth_user.users.count() == 0:
self._logger.debug(__name__, f'Auth user exists but not linked with discord') self._logger.debug(__name__, f"Auth user exists but not linked with discord")
# users = self._users.get_users_by_discord_id(user_dto.user_id) # users = self._users.get_users_by_discord_id(user_dto.user_id)
# add auth_user to user refs # add auth_user to user refs
db_auth_user.oauth_id = None db_auth_user.oauth_id = None
else: else:
# user does not exists # user does not exists
self._logger.debug(__name__, f'Auth user does not exist') self._logger.debug(__name__, f"Auth user does not exist")
try: try:
user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id
except Exception as e: except Exception as e:
self._logger.error(__name__, f'User not found') self._logger.error(__name__, f"User not found")
user_dto.user_id = None user_dto.user_id = None
await self.add_auth_user_async(user_dto) await self.add_auth_user_async(user_dto)
@ -311,46 +311,61 @@ class AuthService(AuthServiceABC):
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None: if update_user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty') raise ServiceException(ServiceErrorCode.InvalidData, f"User is empty")
if update_user_dto.auth_user is None: if update_user_dto.auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty') raise ServiceException(ServiceErrorCode.InvalidData, f"Existing user is empty")
if update_user_dto.new_auth_user is None: if update_user_dto.new_auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty') raise ServiceException(ServiceErrorCode.InvalidData, f"New user is empty")
if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email): if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(
raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail') update_user_dto.new_auth_user.email
):
raise ServiceException(ServiceErrorCode.InvalidData, f"Invalid E-Mail")
user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email) user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email)
if user is None: if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') raise ServiceException(ServiceErrorCode.InvalidUser, "User not found")
if user.confirmation_id is not None: if user.confirmation_id is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') raise ServiceException(ServiceErrorCode.InvalidUser, "E-Mail not confirmed")
# update first name # update first name
if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: if (
update_user_dto.new_auth_user.first_name is not None
and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name
):
user.first_name = update_user_dto.new_auth_user.first_name user.first_name = update_user_dto.new_auth_user.first_name
# update last name # update last name
if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and \ if (
update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name: update_user_dto.new_auth_user.last_name is not None
and update_user_dto.new_auth_user.last_name != ""
and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name
):
user.last_name = update_user_dto.new_auth_user.last_name user.last_name = update_user_dto.new_auth_user.last_name
# update E-Mail # update E-Mail
if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: if (
update_user_dto.new_auth_user.email is not None
and update_user_dto.new_auth_user.email != ""
and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email
):
user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email)
if user_by_new_e_mail is not None: if user_by_new_e_mail is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') raise ServiceException(ServiceErrorCode.InvalidUser, "User already exists")
user.email = update_user_dto.new_auth_user.email user.email = update_user_dto.new_auth_user.email
update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt) update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt)
if update_user_dto.auth_user.password != user.password: if update_user_dto.auth_user.password != user.password:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') raise ServiceException(ServiceErrorCode.InvalidUser, "Wrong password")
# update password # update password
if update_user_dto.new_auth_user.password is not None and self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password: if (
update_user_dto.new_auth_user.password is not None
and self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password
):
user.password_salt = uuid.uuid4() user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
@ -359,20 +374,22 @@ class AuthService(AuthServiceABC):
async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None: if update_user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty') raise ServiceException(ServiceErrorCode.InvalidData, f"User is empty")
if update_user_dto.auth_user is None: if update_user_dto.auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty') raise ServiceException(ServiceErrorCode.InvalidData, f"Existing user is empty")
if update_user_dto.new_auth_user is None: if update_user_dto.new_auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty') raise ServiceException(ServiceErrorCode.InvalidData, f"New user is empty")
if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email): if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(
raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail') update_user_dto.new_auth_user.email
):
raise ServiceException(ServiceErrorCode.InvalidData, f"Invalid E-Mail")
user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email) user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email)
if user is None: if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') raise ServiceException(ServiceErrorCode.InvalidUser, "User not found")
if user.confirmation_id is not None and update_user_dto.new_auth_user.is_confirmed: if user.confirmation_id is not None and update_user_dto.new_auth_user.is_confirmed:
user.confirmation_id = None user.confirmation_id = None
@ -382,27 +399,45 @@ class AuthService(AuthServiceABC):
# raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') # raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed')
# update first name # update first name
if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: if (
update_user_dto.new_auth_user.first_name is not None
and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name
):
user.first_name = update_user_dto.new_auth_user.first_name user.first_name = update_user_dto.new_auth_user.first_name
# update last name # update last name
if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name: if (
update_user_dto.new_auth_user.last_name is not None
and update_user_dto.new_auth_user.last_name != ""
and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name
):
user.last_name = update_user_dto.new_auth_user.last_name user.last_name = update_user_dto.new_auth_user.last_name
# update E-Mail # update E-Mail
if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: if (
update_user_dto.new_auth_user.email is not None
and update_user_dto.new_auth_user.email != ""
and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email
):
user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email)
if user_by_new_e_mail is not None: if user_by_new_e_mail is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') raise ServiceException(ServiceErrorCode.InvalidUser, "User already exists")
user.email = update_user_dto.new_auth_user.email user.email = update_user_dto.new_auth_user.email
# update password # update password
if update_user_dto.new_auth_user.password is not None and update_user_dto.change_password and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt): if (
update_user_dto.new_auth_user.password is not None
and update_user_dto.change_password
and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
):
user.password_salt = uuid.uuid4() user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
# update role # update role
if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role: if (
user.auth_role == update_user_dto.auth_user.auth_role
and user.auth_role != update_user_dto.new_auth_user.auth_role
):
user.auth_role = update_user_dto.new_auth_user.auth_role user.auth_role = update_user_dto.new_auth_user.auth_role
self._auth_users.update_auth_user(user) self._auth_users.update_auth_user(user)
@ -414,43 +449,46 @@ class AuthService(AuthServiceABC):
self._auth_users.delete_auth_user(user) self._auth_users.delete_auth_user(user)
self._db.save_changes() self._db.save_changes()
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Cannot delete user', e) self._logger.error(__name__, f"Cannot delete user", e)
raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {email}') raise ServiceException(ServiceErrorCode.UnableToDelete, f"Cannot delete user by mail {email}")
async def delete_auth_user_async(self, user_dto: AuthUser): async def delete_auth_user_async(self, user_dto: AuthUser):
try: try:
self._auth_users.delete_auth_user(AUT.to_db(user_dto)) self._auth_users.delete_auth_user(AUT.to_db(user_dto))
self._db.save_changes() self._db.save_changes()
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Cannot delete user', e) self._logger.error(__name__, f"Cannot delete user", e)
raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {user_dto.email}') raise ServiceException(
ServiceErrorCode.UnableToDelete,
f"Cannot delete user by mail {user_dto.email}",
)
def verify_login(self, token_str: str) -> bool: def verify_login(self, token_str: str) -> bool:
try: try:
token = self.decode_token(token_str) token = self.decode_token(token_str)
if token is None or 'email' not in token: if token is None or "email" not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') raise ServiceException(ServiceErrorCode.InvalidData, "Token invalid")
user = self._auth_users.find_auth_user_by_email(token['email']) user = self._auth_users.find_auth_user_by_email(token["email"])
if user is None: if user is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') raise ServiceException(ServiceErrorCode.InvalidData, "Token expired")
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Token invalid', e) self._logger.error(__name__, f"Token invalid", e)
return False return False
return True return True
async def login_async(self, user_dto: AuthUser) -> TokenDTO: async def login_async(self, user_dto: AuthUser) -> TokenDTO:
if user_dto is None: if user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set') raise ServiceException(ServiceErrorCode.InvalidData, "User not set")
db_user = self._auth_users.find_auth_user_by_email(user_dto.email) db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is None: if db_user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found') raise ServiceException(ServiceErrorCode.InvalidUser, f"User not found")
user_dto.password = self._hash_sha256(user_dto.password, db_user.password_salt) user_dto.password = self._hash_sha256(user_dto.password, db_user.password_salt)
if db_user.password != user_dto.password: if db_user.password != user_dto.password:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') raise ServiceException(ServiceErrorCode.InvalidUser, "Wrong password")
token = self.generate_token(db_user) token = self.generate_token(db_user)
refresh_token = self._create_and_save_refresh_token(db_user) refresh_token = self._create_and_save_refresh_token(db_user)
@ -462,7 +500,7 @@ class AuthService(AuthServiceABC):
async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO: async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO:
if user_dto is None: if user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set') raise ServiceException(ServiceErrorCode.InvalidData, "User not set")
db_user = self._auth_users.find_auth_user_by_email(user_dto.email) db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is None: if db_user is None:
@ -480,38 +518,46 @@ class AuthService(AuthServiceABC):
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO:
if token_dto is None: if token_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') raise ServiceException(ServiceErrorCode.InvalidData, f"Token not set")
try: try:
token = self.decode_token(token_dto.token) token = self.decode_token(token_dto.token)
if token is None or 'email' not in token: if token is None or "email" not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') raise ServiceException(ServiceErrorCode.InvalidData, "Token invalid")
user = self._auth_users.get_auth_user_by_email(token['email']) user = self._auth_users.get_auth_user_by_email(token["email"])
if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): if (
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') user is None
or user.refresh_token != token_dto.refresh_token
or user.refresh_token_expire_time <= datetime.now()
):
raise ServiceException(ServiceErrorCode.InvalidData, "Token expired")
return TokenDTO(self.generate_token(user), self._create_and_save_refresh_token(user)) return TokenDTO(self.generate_token(user), self._create_and_save_refresh_token(user))
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Refreshing token failed', e) self._logger.error(__name__, f"Refreshing token failed", e)
return TokenDTO('', '') return TokenDTO("", "")
async def revoke_async(self, token_dto: TokenDTO): async def revoke_async(self, token_dto: TokenDTO):
if token_dto is None or token_dto.token is None or token_dto.refresh_token is None: if token_dto is None or token_dto.token is None or token_dto.refresh_token is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token not set') raise ServiceException(ServiceErrorCode.InvalidData, "Token not set")
try: try:
token = self.decode_token(token_dto.token) token = self.decode_token(token_dto.token)
user = self._auth_users.get_auth_user_by_email(token['email']) user = self._auth_users.get_auth_user_by_email(token["email"])
if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): if (
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') user is None
or user.refresh_token != token_dto.refresh_token
or user.refresh_token_expire_time <= datetime.now()
):
raise ServiceException(ServiceErrorCode.InvalidData, "Token expired")
user.refresh_token = None user.refresh_token = None
self._auth_users.update_auth_user(user) self._auth_users.update_auth_user(user)
self._db.save_changes() self._db.save_changes()
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Refreshing token failed', e) self._logger.error(__name__, f"Refreshing token failed", e)
async def confirm_email_async(self, id: str) -> bool: async def confirm_email_async(self, id: str) -> bool:
user = self._auth_users.find_auth_user_by_confirmation_id(id) user = self._auth_users.find_auth_user_by_confirmation_id(id)
@ -540,13 +586,16 @@ class AuthService(AuthServiceABC):
async def reset_password_async(self, rp_dto: ResetPasswordDTO): async def reset_password_async(self, rp_dto: ResetPasswordDTO):
user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id) user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id)
if user is None: if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, f'User by forgot password id {rp_dto.id} not found') raise ServiceException(
ServiceErrorCode.InvalidUser,
f"User by forgot password id {rp_dto.id} not found",
)
if user.confirmation_id is not None: if user.confirmation_id is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, f'E-Mail not confirmed') raise ServiceException(ServiceErrorCode.InvalidUser, f"E-Mail not confirmed")
if user.password is None or rp_dto.password == '': if user.password is None or rp_dto.password == "":
raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set') raise ServiceException(ServiceErrorCode.InvalidData, f"Password not set")
user.password_salt = uuid.uuid4() user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(rp_dto.password, user.password_salt) user.password = self._hash_sha256(rp_dto.password, user.password_salt)

View File

@ -20,14 +20,13 @@ from bot_data.model.server import Server
class DiscordService: class DiscordService:
def __init__( def __init__(
self, self,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
servers: ServerRepositoryABC, servers: ServerRepositoryABC,
auth: AuthServiceABC, auth: AuthServiceABC,
auth_users: AuthUserRepositoryABC, auth_users: AuthUserRepositoryABC,
users: UserRepositoryABC, users: UserRepositoryABC,
): ):
self._bot = bot self._bot = bot
self._servers = servers self._servers = servers
@ -38,64 +37,53 @@ class DiscordService:
def _to_dto(self, x: Server) -> Optional[ServerDTO]: def _to_dto(self, x: Server) -> Optional[ServerDTO]:
guild = self._bot.get_guild(x.discord_server_id) guild = self._bot.get_guild(x.discord_server_id)
if guild is None: if guild is None:
return ServerTransformer.to_dto( return ServerTransformer.to_dto(x, "", 0, None)
x,
'',
0,
None
)
return ServerTransformer.to_dto( return ServerTransformer.to_dto(x, guild.name, guild.member_count, guild.icon)
x,
guild.name,
guild.member_count,
guild.icon
)
async def get_all_servers(self) -> List[ServerDTO]: async def get_all_servers(self) -> List[ServerDTO]:
servers = List(ServerDTO, self._servers.get_servers()) servers = List(ServerDTO, self._servers.get_servers())
return servers.select(self._to_dto).where(lambda x: x.name != '') return servers.select(self._to_dto).where(lambda x: x.name != "")
async def get_all_servers_by_user(self) -> List[ServerDTO]: async def get_all_servers_by_user(self) -> List[ServerDTO]:
token = self._auth.get_decoded_token_from_request() token = self._auth.get_decoded_token_from_request()
if token is None or 'email' not in token or 'role' not in token: if token is None or "email" not in token or "role" not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') raise ServiceException(ServiceErrorCode.InvalidData, "Token invalid")
role = AuthRoleEnum(token['role']) role = AuthRoleEnum(token["role"])
servers = self._servers.get_servers() servers = self._servers.get_servers()
if role != AuthRoleEnum.admin: if role != AuthRoleEnum.admin:
auth_user = self._auth_users.find_auth_user_by_email(token['email']) auth_user = self._auth_users.find_auth_user_by_email(token["email"])
if auth_user is not None: if auth_user is not None:
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id) user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
servers = servers.where(lambda x: x.server_id in user_ids) servers = servers.where(lambda x: x.server_id in user_ids)
servers = List(ServerDTO, servers) servers = List(ServerDTO, servers)
return servers.select(self._to_dto).where(lambda x: x.name != '') return servers.select(self._to_dto).where(lambda x: x.name != "")
async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO: async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO:
token = self._auth.get_decoded_token_from_request() token = self._auth.get_decoded_token_from_request()
if token is None or 'email' not in token or 'role' not in token: if token is None or "email" not in token or "role" not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') raise ServiceException(ServiceErrorCode.InvalidData, "Token invalid")
role = AuthRoleEnum(token['role']) role = AuthRoleEnum(token["role"])
filtered_result = self._servers.get_filtered_servers(criteria) filtered_result = self._servers.get_filtered_servers(criteria)
# filter out servers, where the user not exists # filter out servers, where the user not exists
if role != AuthRoleEnum.admin: if role != AuthRoleEnum.admin:
auth_user = self._auth_users.find_auth_user_by_email(token['email']) auth_user = self._auth_users.find_auth_user_by_email(token["email"])
if auth_user is not None: if auth_user is not None:
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id) user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
filtered_result.result = filtered_result.result.where(lambda x: x.server_id in user_ids) filtered_result.result = filtered_result.result.where(lambda x: x.server_id in user_ids)
servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != '') servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != "")
result = List(ServerDTO, servers) result = List(ServerDTO, servers)
if criteria.name is not None and criteria.name != '': if criteria.name is not None and criteria.name != "":
result = result.where(lambda x: criteria.name.lower() in x.name.lower() or x.name.lower() == criteria.name.lower()) result = result.where(
lambda x: criteria.name.lower() in x.name.lower() or x.name.lower() == criteria.name.lower()
)
return ServerFilteredResultDTO( return ServerFilteredResultDTO(List(ServerDTO, result), servers.count())
List(ServerDTO, result),
servers.count()
)
async def get_server_by_id_async(self, id: int) -> ServerDTO: async def get_server_by_id_async(self, id: int) -> ServerDTO:
server = self._servers.get_server_by_id(id) server = self._servers.get_server_by_id(id)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_api.transformer' __title__ = "bot_api.transformer"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -7,7 +7,6 @@ from bot_data.model.auth_user import AuthUser
class AuthUserTransformer(TransformerABC): class AuthUserTransformer(TransformerABC):
@staticmethod @staticmethod
def to_db(dto: AuthUserDTO) -> AuthUser: def to_db(dto: AuthUserDTO) -> AuthUser:
return AuthUser( return AuthUser(
@ -22,7 +21,7 @@ class AuthUserTransformer(TransformerABC):
None, None,
datetime.now(), datetime.now(),
AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role),
auth_user_id=0 if dto.id is None else dto.id auth_user_id=0 if dto.id is None else dto.id,
) )
@staticmethod @staticmethod
@ -32,7 +31,7 @@ class AuthUserTransformer(TransformerABC):
db.first_name, db.first_name,
db.last_name, db.last_name,
db.email, db.email,
'' if password is None else password, "" if password is None else password,
db.confirmation_id, db.confirmation_id,
db.auth_role db.auth_role,
) )

View File

@ -8,7 +8,6 @@ from bot_data.model.server import Server
class ServerTransformer(TransformerABC): class ServerTransformer(TransformerABC):
@staticmethod @staticmethod
def to_db(dto: ServerDTO) -> Server: def to_db(dto: ServerDTO) -> Server:
return Server(dto.discord_id) return Server(dto.discord_id)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core' __title__ = "bot_core"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports # imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core.abc' __title__ = "bot_core.abc"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -0,0 +1,61 @@
from abc import ABC, abstractmethod
from datetime import datetime
from typing import Callable
from cpl_query.extension import List
from discord.ext.commands import Context
from bot_data.model.user import User
from modules.base.configuration.base_server_settings import BaseServerSettings
class ClientUtilsABC(ABC):
@abstractmethod
def __init__(self):
pass
@abstractmethod
def received_command(self, guild_id: int):
pass
@abstractmethod
def moved_user(self, guild_id: int):
pass
@abstractmethod
def moved_users(self, guild_id: int, count: int):
pass
@abstractmethod
def get_client(self, dc_ic: int, guild_id: int):
pass
@abstractmethod
async def check_if_bot_is_ready_yet(self) -> bool:
pass
@abstractmethod
async def check_if_bot_is_ready_yet_and_respond(self, ctx: Context) -> bool:
pass
@abstractmethod
async def presence_game(self, t_key: str):
pass
@abstractmethod
def get_auto_complete_list(self, _l: List, current: str, select: Callable = None) -> List:
pass
@abstractmethod
def is_message_xp_count_by_hour_higher_that_max_message_count_per_hour(
self,
created_at: datetime,
user: User,
settings: BaseServerSettings,
is_reaction: bool = False,
) -> bool:
pass
@abstractmethod
def get_ontime_for_user(self, user: User) -> float:
pass

View File

@ -1,35 +0,0 @@
from abc import ABC, abstractmethod
from typing import Callable
from cpl_query.extension import List
from discord.ext.commands import Context
class ClientUtilsServiceABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def received_command(self, guild_id: int): pass
@abstractmethod
def moved_user(self, guild_id: int): pass
@abstractmethod
def moved_users(self, guild_id: int, count: int): pass
@abstractmethod
def get_client(self, dc_ic: int, guild_id: int): pass
@abstractmethod
async def check_if_bot_is_ready_yet(self) -> bool: pass
@abstractmethod
async def check_if_bot_is_ready_yet_and_respond(self, ctx: Context) -> bool: pass
@abstractmethod
async def presence_game(self, t_key: str): pass
@abstractmethod
def get_auto_complete_list(self, _l: List, current: str, select: Callable = None) -> List: pass

View File

@ -9,11 +9,16 @@ from bot_core.configuration.file_logging_settings import FileLoggingSettings
class CustomFileLoggerABC(Logger, ABC): class CustomFileLoggerABC(Logger, ABC):
@abstractmethod @abstractmethod
def __init__(self, key: str, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC): def __init__(
self,
key: str,
config: ConfigurationABC,
time_format: TimeFormatSettings,
env: ApplicationEnvironmentABC,
):
self._key = key self._key = key
self._settings: LoggingSettings = config.get_configuration(f'{FileLoggingSettings.__name__}_{key}') self._settings: LoggingSettings = config.get_configuration(f"{FileLoggingSettings.__name__}_{key}")
Logger.__init__(self, self._settings, time_format, env) Logger.__init__(self, self._settings, time_format, env)
self._begin_log() self._begin_log()
@ -24,41 +29,41 @@ class CustomFileLoggerABC(Logger, ABC):
def _begin_log(self): def _begin_log(self):
console_level = self._console.value console_level = self._console.value
self._console = LoggingLevelEnum.OFF self._console = LoggingLevelEnum.OFF
self.info(__name__, f'Starting...') self.info(__name__, f"Starting...")
self._console = LoggingLevelEnum(console_level) self._console = LoggingLevelEnum(console_level)
def _get_string(self, name_list_as_str: str, level: LoggingLevelEnum, message: str) -> str: def _get_string(self, name_list_as_str: str, level: LoggingLevelEnum, message: str) -> str:
names = name_list_as_str.split(' ') names = name_list_as_str.split(" ")
log_level = level.name log_level = level.name
string = f'<{self._get_datetime_now()}> [ {log_level} ]' string = f"<{self._get_datetime_now()}> [ {log_level} ]"
for name in names: for name in names:
string += f' [ {name} ]' string += f" [ {name} ]"
string += f': {message}' string += f": {message}"
return string return string
def header(self, string: str): def header(self, string: str):
super().header(string) super().header(string)
def trace(self, name: str, message: str): def trace(self, name: str, message: str):
name = f'{name} {self._key}' name = f"{name} {self._key}"
super().trace(name, message) super().trace(name, message)
def debug(self, name: str, message: str): def debug(self, name: str, message: str):
name = f'{name} {self._key}' name = f"{name} {self._key}"
super().debug(name, message) super().debug(name, message)
def info(self, name: str, message: str): def info(self, name: str, message: str):
name = f'{name} {self._key}' name = f"{name} {self._key}"
super().info(name, message) super().info(name, message)
def warn(self, name: str, message: str): def warn(self, name: str, message: str):
name = f'{name} {self._key}' name = f"{name} {self._key}"
super().warn(name, message) super().warn(name, message)
def error(self, name: str, message: str, ex: Exception = None): def error(self, name: str, message: str, ex: Exception = None):
name = f'{name} {self._key}' name = f"{name} {self._key}"
super().error(name, message, ex) super().error(name, message, ex)
def fatal(self, name: str, message: str, ex: Exception = None): def fatal(self, name: str, message: str, ex: Exception = None):
name = f'{name} {self._key}' name = f"{name} {self._key}"
super().fatal(name, message, ex) super().fatal(name, message, ex)

View File

@ -1,5 +1,5 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Union from typing import Union, Optional
import discord import discord
from cpl_query.extension import List from cpl_query.extension import List
@ -8,24 +8,58 @@ from discord.ext.commands import Context
class MessageServiceABC(ABC): class MessageServiceABC(ABC):
@abstractmethod
def __init__(self):
pass
@abstractmethod @abstractmethod
def __init__(self): pass async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False):
pass
@abstractmethod @abstractmethod
async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False): pass async def delete_message(self, message: discord.Message, without_tracking=False):
pass
@abstractmethod @abstractmethod
async def delete_message(self, message: discord.Message, without_tracking=False): pass async def send_channel_message(
self,
channel: discord.TextChannel,
message: Union[str, discord.Embed],
without_tracking=True,
):
pass
@abstractmethod @abstractmethod
async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed], without_tracking=True): pass async def send_dm_message(
self,
message: Union[str, discord.Embed],
receiver: Union[discord.User, discord.Member],
without_tracking=False,
):
pass
@abstractmethod @abstractmethod
async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member], without_tracking=False): pass async def send_ctx_msg(
self,
ctx: Context,
message: Union[str, discord.Embed],
file: discord.File = None,
is_persistent: bool = False,
is_public: bool = False,
wait_before_delete: int = None,
without_tracking=True,
) -> Optional[discord.Message]:
pass
@abstractmethod @abstractmethod
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, is_public: bool = False, wait_before_delete: int = None, without_tracking=True): pass async def send_interaction_msg(
self,
@abstractmethod interaction: Interaction,
async def send_interaction_msg(self, interaction: Interaction, message: Union[str, discord.Embed], is_persistent: bool = False, is_public: bool = False, wait_before_delete: int = None, without_tracking=True, **kwargs): pass message: Union[str, discord.Embed],
is_persistent: bool = False,
is_public: bool = False,
wait_before_delete: int = None,
without_tracking=True,
**kwargs
):
pass

View File

@ -7,7 +7,6 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
class ModuleABC(StartupExtensionABC): class ModuleABC(StartupExtensionABC):
@abstractmethod @abstractmethod
def __init__(self, dc: DiscordCollectionABC, feature_flag: FeatureFlagsEnum): def __init__(self, dc: DiscordCollectionABC, feature_flag: FeatureFlagsEnum):
StartupExtensionABC.__init__(self) StartupExtensionABC.__init__(self)

View File

@ -4,7 +4,7 @@
"Version": { "Version": {
"Major": "0", "Major": "0",
"Minor": "3", "Minor": "3",
"Micro": "0" "Micro": "1"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de", "AuthorEmail": "sven.heidemann@sh-edraft.de",

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core.configuration' __title__ = "bot_core.configuration"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -8,7 +8,6 @@ from bot_core.configuration.file_logging_settings import FileLoggingSettings
class BotLoggingSettings(ConfigurationModelABC): class BotLoggingSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._files: List[FileLoggingSettings] = List(FileLoggingSettings) self._files: List[FileLoggingSettings] = List(FileLoggingSettings)
@ -22,12 +21,12 @@ class BotLoggingSettings(ConfigurationModelABC):
files = List(FileLoggingSettings) files = List(FileLoggingSettings)
for s in settings: for s in settings:
st = FileLoggingSettings() st = FileLoggingSettings()
settings[s]['Key'] = s settings[s]["Key"] = s
st.from_dict(settings[s]) st.from_dict(settings[s])
files.append(st) files.append(st)
self._files = files self._files = files
except Exception as e: except Exception as e:
Console.set_foreground_color(ForegroundColorEnum.red) Console.set_foreground_color(ForegroundColorEnum.red)
Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.write_line(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.write_line(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
Console.set_foreground_color(ForegroundColorEnum.default) Console.set_foreground_color(ForegroundColorEnum.default)

View File

@ -8,7 +8,6 @@ from bot_core.configuration.server_settings import ServerSettings
class BotSettings(ConfigurationModelABC): class BotSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
@ -16,7 +15,8 @@ class BotSettings(ConfigurationModelABC):
self._technicians: List[int] = List(int) self._technicians: List[int] = List(int)
self._wait_for_restart = 2 self._wait_for_restart = 2
self._wait_for_shutdown = 2 self._wait_for_shutdown = 2
self._cache_max_messages = 1000
@property @property
def servers(self) -> List[ServerSettings]: def servers(self) -> List[ServerSettings]:
return self._servers return self._servers
@ -33,6 +33,10 @@ class BotSettings(ConfigurationModelABC):
def wait_for_shutdown(self) -> int: def wait_for_shutdown(self) -> int:
return self._wait_for_shutdown return self._wait_for_shutdown
@property
def cache_max_messages(self) -> int:
return self._cache_max_messages
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._technicians = settings["Technicians"] self._technicians = settings["Technicians"]
@ -41,6 +45,11 @@ class BotSettings(ConfigurationModelABC):
settings.pop("Technicians") settings.pop("Technicians")
settings.pop("WaitForRestart") settings.pop("WaitForRestart")
settings.pop("WaitForShutdown") settings.pop("WaitForShutdown")
if "CacheMaxMessages" in settings:
self._cache_max_messages = settings["CacheMaxMessages"]
settings.pop("CacheMaxMessages")
servers = List(ServerSettings) servers = List(ServerSettings)
for s in settings: for s in settings:
st = ServerSettings() st = ServerSettings()
@ -49,5 +58,5 @@ class BotSettings(ConfigurationModelABC):
servers.append(st) servers.append(st)
self._servers = servers self._servers = servers
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -3,19 +3,19 @@ from enum import Enum
class FeatureFlagsEnum(Enum): class FeatureFlagsEnum(Enum):
# modules # modules
api_module = 'ApiModule' api_module = "ApiModule"
admin_module = 'AdminModule' admin_module = "AdminModule"
auto_role_module = 'AutoRoleModule' auto_role_module = "AutoRoleModule"
base_module = 'BaseModule' base_module = "BaseModule"
boot_log_module = 'BootLogModule' boot_log_module = "BootLogModule"
core_module = 'CoreModule' core_module = "CoreModule"
core_extension_module = 'CoreExtensionModule' core_extension_module = "CoreExtensionModule"
data_module = 'DataModule', data_module = ("DataModule",)
database_module = 'DatabaseModule', database_module = ("DatabaseModule",)
level_module = 'LevelModule' level_module = "LevelModule"
moderator_module = 'ModeratorModule' moderator_module = "ModeratorModule"
permission_module = 'PermissionModule' permission_module = "PermissionModule"
stats_module = 'StatsModule' stats_module = "StatsModule"
# features # features
api_only = 'ApiOnly' api_only = "ApiOnly"
presence = 'Presence' presence = "Presence"

View File

@ -8,7 +8,6 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
class FeatureFlagsSettings(ConfigurationModelABC): class FeatureFlagsSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
@ -47,5 +46,5 @@ class FeatureFlagsSettings(ConfigurationModelABC):
for flag in [f.value for f in FeatureFlagsEnum]: for flag in [f.value for f in FeatureFlagsEnum]:
self._load_flag(settings, FeatureFlagsEnum(flag)) self._load_flag(settings, FeatureFlagsEnum(flag))
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -5,11 +5,10 @@ from cpl_core.logging import LoggingSettings
class FileLoggingSettings(LoggingSettings): class FileLoggingSettings(LoggingSettings):
def __init__(self): def __init__(self):
LoggingSettings.__init__(self) LoggingSettings.__init__(self)
self._key = '' self._key = ""
@property @property
def key(self) -> str: def key(self) -> str:
@ -17,8 +16,8 @@ class FileLoggingSettings(LoggingSettings):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._key = settings['Key'] self._key = settings["Key"]
super().from_dict(settings) super().from_dict(settings)
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -5,7 +5,6 @@ from cpl_core.console import Console
class ServerSettings(ConfigurationModelABC): class ServerSettings(ConfigurationModelABC):
def __init__(self): def __init__(self):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
@ -22,8 +21,8 @@ class ServerSettings(ConfigurationModelABC):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._id = int(settings['Id']) self._id = int(settings["Id"])
self._message_delete_timer = int(settings['MessageDeleteTimer']) self._message_delete_timer = int(settings["MessageDeleteTimer"])
except Exception as e: except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in settings') Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in settings")
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core.core_extension' __title__ = "bot_core.core_extension"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -3,7 +3,7 @@ from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC from cpl_core.dependency_injection import ServiceProviderABC
from cpl_translation import TranslatePipe from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
@ -13,7 +13,6 @@ from modules.permission.abc.permission_service_abc import PermissionServiceABC
class CoreExtension(ApplicationExtensionABC): class CoreExtension(ApplicationExtensionABC):
def __init__(self): def __init__(self):
ApplicationExtensionABC.__init__(self) ApplicationExtensionABC.__init__(self)
@ -23,7 +22,7 @@ class CoreExtension(ApplicationExtensionABC):
return return
permissions: PermissionServiceABC = services.get_service(PermissionServiceABC) permissions: PermissionServiceABC = services.get_service(PermissionServiceABC)
client_utils: ClientUtilsServiceABC = services.get_service(ClientUtilsServiceABC) client_utils: ClientUtilsABC = services.get_service(ClientUtilsABC)
message_service: MessageServiceABC = services.get_service(MessageServiceABC) message_service: MessageServiceABC = services.get_service(MessageServiceABC)
t: TranslatePipe = services.get_service(TranslatePipe) t: TranslatePipe = services.get_service(TranslatePipe)
CommandChecks.init(permissions, client_utils, message_service, t) CommandChecks.init(permissions, client_utils, message_service, t)

View File

@ -6,11 +6,12 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.module_abc import ModuleABC from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.core_extension.core_extension_on_ready_event import CoreExtensionOnReadyEvent from bot_core.core_extension.core_extension_on_ready_event import (
CoreExtensionOnReadyEvent,
)
class CoreExtensionModule(ModuleABC): class CoreExtensionModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC): def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.core_extension_module) ModuleABC.__init__(self, dc, FeatureFlagsEnum.core_extension_module)

View File

@ -5,17 +5,16 @@ from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.client_utils_abc import ClientUtilsABC
class CoreExtensionOnReadyEvent(OnReadyABC): class CoreExtensionOnReadyEvent(OnReadyABC):
def __init__( def __init__(
self, self,
logger: LoggerABC, logger: LoggerABC,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
client_utils: ClientUtilsServiceABC, client_utils: ClientUtilsABC,
t: TranslatePipe t: TranslatePipe,
): ):
OnReadyABC.__init__(self) OnReadyABC.__init__(self)
@ -24,9 +23,9 @@ class CoreExtensionOnReadyEvent(OnReadyABC):
self._client_utils = client_utils self._client_utils = client_utils
self._t = t self._t = t
self._logger.info(__name__, f'Module {type(self)} loaded') self._logger.info(__name__, f"Module {type(self)} loaded")
async def on_ready(self): async def on_ready(self):
self._logger.debug(__name__, f'Module {type(self)} started') self._logger.debug(__name__, f"Module {type(self)} started")
await self._client_utils.presence_game('common.presence.running') await self._client_utils.presence_game("common.presence.running")
self._logger.trace(__name__, f'Module {type(self)} stopped') self._logger.trace(__name__, f"Module {type(self)} stopped")

View File

@ -4,7 +4,7 @@ from cpl_core.environment import ApplicationEnvironmentABC
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
from cpl_discord.service.discord_collection_abc import DiscordCollectionABC from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.abc.module_abc import ModuleABC from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
@ -15,7 +15,6 @@ from bot_core.service.message_service import MessageService
class CoreModule(ModuleABC): class CoreModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC): def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.core_module) ModuleABC.__init__(self, dc, FeatureFlagsEnum.core_module)
@ -24,7 +23,7 @@ class CoreModule(ModuleABC):
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_transient(MessageServiceABC, MessageService) services.add_transient(MessageServiceABC, MessageService)
services.add_transient(ClientUtilsServiceABC, ClientUtilsService) services.add_transient(ClientUtilsABC, ClientUtilsService)
# pipes # pipes
services.add_transient(DateTimeOffsetPipe) services.add_transient(DateTimeOffsetPipe)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core.events' __title__ = "bot_core.events"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -3,17 +3,16 @@ from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.client_utils_abc import ClientUtilsABC
class CoreOnReadyEvent(OnReadyABC): class CoreOnReadyEvent(OnReadyABC):
def __init__( def __init__(
self, self,
logger: LoggerABC, logger: LoggerABC,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
client_utils: ClientUtilsServiceABC, client_utils: ClientUtilsABC,
t: TranslatePipe, t: TranslatePipe,
): ):
OnReadyABC.__init__(self) OnReadyABC.__init__(self)
@ -22,9 +21,9 @@ class CoreOnReadyEvent(OnReadyABC):
self._client_utils = client_utils self._client_utils = client_utils
self._t = t self._t = t
self._logger.info(__name__, f'Module {type(self)} loaded') self._logger.info(__name__, f"Module {type(self)} loaded")
async def on_ready(self): async def on_ready(self):
self._logger.debug(__name__, f'Module {type(self)} started') self._logger.debug(__name__, f"Module {type(self)} started")
await self._client_utils.presence_game('common.presence.booting') await self._client_utils.presence_game("common.presence.booting")
self._logger.trace(__name__, f'Module {type(self)} stopped') self._logger.trace(__name__, f"Module {type(self)} stopped")

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core.exception' __title__ = "bot_core.exception"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -2,6 +2,5 @@ from discord.ext.commands import CommandError
class CheckError(CommandError): class CheckError(CommandError):
def __init__(self, message, *args): def __init__(self, message, *args):
CommandError.__init__(self, message, *args) CommandError.__init__(self, message, *args)

View File

@ -6,21 +6,21 @@ bot Keksdose bot
Discord bot for the Keksdose discord Server Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de :copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__title__ = 'bot_core.helper' __title__ = "bot_core.helper"
__author__ = 'Sven Heidemann' __author__ = "Sven Heidemann"
__license__ = 'MIT' __license__ = "MIT"
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = '0.3.0' __version__ = "0.3.1"
from collections import namedtuple from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major='0', minor='3', micro='0') version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -4,7 +4,7 @@ from cpl_translation import TranslatePipe
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.exception.check_error import CheckError from bot_core.exception.check_error import CheckError
from modules.permission.abc.permission_service_abc import PermissionServiceABC from modules.permission.abc.permission_service_abc import PermissionServiceABC
@ -12,17 +12,17 @@ from modules.permission.abc.permission_service_abc import PermissionServiceABC
class CommandChecks: class CommandChecks:
_permissions: Optional[PermissionServiceABC] = None _permissions: Optional[PermissionServiceABC] = None
_client_utils: Optional[ClientUtilsServiceABC] = None _client_utils: Optional[ClientUtilsABC] = None
_message_service: Optional[MessageServiceABC] = None _message_service: Optional[MessageServiceABC] = None
_t: Optional[TranslatePipe] = None _t: Optional[TranslatePipe] = None
@classmethod @classmethod
def init( def init(
cls, cls,
permissions: PermissionServiceABC, permissions: PermissionServiceABC,
client_utils: ClientUtilsServiceABC, client_utils: ClientUtilsABC,
message_service: MessageServiceABC, message_service: MessageServiceABC,
translate: TranslatePipe, translate: TranslatePipe,
): ):
cls._permissions = permissions cls._permissions = permissions
cls._client_utils = client_utils cls._client_utils = client_utils
@ -34,7 +34,7 @@ class CommandChecks:
async def check_if_bot_is_ready_yet_and_respond(ctx: Context) -> bool: async def check_if_bot_is_ready_yet_and_respond(ctx: Context) -> bool:
result = await cls._client_utils.check_if_bot_is_ready_yet_and_respond(ctx) result = await cls._client_utils.check_if_bot_is_ready_yet_and_respond(ctx)
if not result: if not result:
raise CheckError(f'Bot is not ready') raise CheckError(f"Bot is not ready")
return result return result
return commands.check(check_if_bot_is_ready_yet_and_respond) return commands.check(check_if_bot_is_ready_yet_and_respond)
@ -44,8 +44,8 @@ class CommandChecks:
async def check_is_member_admin(ctx: Context): async def check_is_member_admin(ctx: Context):
has_permission = cls._permissions.is_member_admin(ctx.author) has_permission = cls._permissions.is_member_admin(ctx.author)
if not has_permission: if not has_permission:
await cls._message_service.send_ctx_msg(ctx, cls._t.transform('common.no_permission_message')) await cls._message_service.send_ctx_msg(ctx, cls._t.transform("common.no_permission_message"))
raise CheckError(f'Member {ctx.author.name} is not admin') raise CheckError(f"Member {ctx.author.name} is not admin")
return has_permission return has_permission
@ -56,8 +56,8 @@ class CommandChecks:
async def check_is_member_technician(ctx: Context): async def check_is_member_technician(ctx: Context):
has_permission = cls._permissions.is_member_technician(ctx.author) has_permission = cls._permissions.is_member_technician(ctx.author)
if not has_permission: if not has_permission:
await cls._message_service.send_ctx_msg(ctx, cls._t.transform('common.no_permission_message')) await cls._message_service.send_ctx_msg(ctx, cls._t.transform("common.no_permission_message"))
raise CheckError(f'Member {ctx.author.name} is not technician') raise CheckError(f"Member {ctx.author.name} is not technician")
return has_permission return has_permission
@ -68,8 +68,8 @@ class CommandChecks:
async def check_is_member_moderator(ctx: Context): async def check_is_member_moderator(ctx: Context):
has_permission = cls._permissions.is_member_moderator(ctx.author) has_permission = cls._permissions.is_member_moderator(ctx.author)
if not has_permission: if not has_permission:
await cls._message_service.send_ctx_msg(ctx, cls._t.transform('common.no_permission_message')) await cls._message_service.send_ctx_msg(ctx, cls._t.transform("common.no_permission_message"))
raise CheckError(f'Member {ctx.author.name} is not moderator') raise CheckError(f"Member {ctx.author.name} is not moderator")
return has_permission return has_permission

Some files were not shown because too many files have changed in this diff Show More