From 164671a07c2391f2cc560e1ecc400ae44ef734d2 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 6 Nov 2022 21:34:58 +0100 Subject: [PATCH] Added logic to handle level by xp #25 --- .../service/level_repository_service.py | 2 +- .../level/configuration/level_settings.py | 8 ++- kdb-bot/src/modules/level/default-level.json | 55 ++++++++++--------- kdb-bot/src/modules/level/events/__init__.py | 26 +++++++++ .../level/events/level_on_message_event.py | 21 +++++++ .../level_on_voice_state_update_event.py | 23 ++++++++ kdb-bot/src/modules/level/level_module.py | 6 ++ kdb-bot/src/modules/level/level_seeder.py | 12 ++-- .../modules/level/service/level_service.py | 19 ++++++- 9 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 kdb-bot/src/modules/level/events/__init__.py create mode 100644 kdb-bot/src/modules/level/events/level_on_message_event.py create mode 100644 kdb-bot/src/modules/level/events/level_on_voice_state_update_event.py diff --git a/kdb-bot/src/bot_data/service/level_repository_service.py b/kdb-bot/src/bot_data/service/level_repository_service.py index 37ee595298..3e41fc1b4b 100644 --- a/kdb-bot/src/bot_data/service/level_repository_service.py +++ b/kdb-bot/src/bot_data/service/level_repository_service.py @@ -63,7 +63,7 @@ class LevelRepositoryService(LevelRepositoryABC): def get_levels_by_server_id(self, server_id: int) -> List[Level]: levels = List(Level) self._logger.trace(__name__, f'Send SQL command: {Level.get_select_by_server_id_string(server_id)}') - results = self._context.select(Level.get_select_by_server_id_string(server_id))[0] + results = self._context.select(Level.get_select_by_server_id_string(server_id)) for result in results: self._logger.trace(__name__, f'Get level with id {result[0]}') diff --git a/kdb-bot/src/modules/level/configuration/level_settings.py b/kdb-bot/src/modules/level/configuration/level_settings.py index 95dda2c862..6f38e31b1a 100644 --- a/kdb-bot/src/modules/level/configuration/level_settings.py +++ b/kdb-bot/src/modules/level/configuration/level_settings.py @@ -13,14 +13,20 @@ class LevelSettings(ConfigurationModelABC): ConfigurationModelABC.__init__(self) self._levels = List(Level) + self._level_header = '' @property def levels(self) -> List[Level]: return self._levels + @property + def level_header(self) -> str: + return self._level_header + def from_dict(self, settings: dict): try: - for level in settings: + self._level_header = settings['LevelHeader'] + for level in settings['Levels']: self._levels.append(Level( level['Name'], level['Color'], diff --git a/kdb-bot/src/modules/level/default-level.json b/kdb-bot/src/modules/level/default-level.json index 04cb874550..451e7544cd 100644 --- a/kdb-bot/src/modules/level/default-level.json +++ b/kdb-bot/src/modules/level/default-level.json @@ -1,28 +1,31 @@ { - "Level": [ - { - "Name": "Newbie", - "Color": "0x1abc9c", - "MinXp": 0, - "Permissions": 968552209984 - }, - { - "Name": "Keks", - "Color": "0x2ecc71", - "MinXp": 100, - "Permissions": 1002928856640 - }, - { - "Name": "Doppelkeks", - "Color": "0x3498db", - "MinXp": 200, - "Permissions": 1071849660224 - }, - { - "Name": "Auror", - "Color": "0xf1c40f", - "MinXp": 300, - "Permissions": 1089042120513 - } - ] + "Level": { + "LevelHeader": "~~~ Level ~~~", + "Levels": [ + { + "Name": "Newbie", + "Color": "0x1abc9c", + "MinXp": 0, + "Permissions": 968552209984 + }, + { + "Name": "Keks", + "Color": "0x2ecc71", + "MinXp": 100, + "Permissions": 1002928856640 + }, + { + "Name": "Doppelkeks", + "Color": "0x3498db", + "MinXp": 200, + "Permissions": 1071849660224 + }, + { + "Name": "Auror", + "Color": "0xf1c40f", + "MinXp": 300, + "Permissions": 1089042120513 + } + ] + } } \ No newline at end of file diff --git a/kdb-bot/src/modules/level/events/__init__.py b/kdb-bot/src/modules/level/events/__init__.py new file mode 100644 index 0000000000..85e09931a0 --- /dev/null +++ b/kdb-bot/src/modules/level/events/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'modules.base.events' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.3.dev70' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='3', micro='dev70') diff --git a/kdb-bot/src/modules/level/events/level_on_message_event.py b/kdb-bot/src/modules/level/events/level_on_message_event.py new file mode 100644 index 0000000000..cd69622e07 --- /dev/null +++ b/kdb-bot/src/modules/level/events/level_on_message_event.py @@ -0,0 +1,21 @@ +import discord +from cpl_discord.events import OnMessageABC + +from bot_core.logging.message_logger import MessageLogger +from modules.level.service.level_service import LevelService + + +class LevelOnMessageEvent(OnMessageABC): + + def __init__( + self, + logger: MessageLogger, + level: LevelService + ): + OnMessageABC.__init__(self) + self._logger = logger + self._level = level + + async def on_message(self, message: discord.Message): + self._logger.debug(__name__, f'Module {type(self)} started') + await self._level.check_level(message.author) diff --git a/kdb-bot/src/modules/level/events/level_on_voice_state_update_event.py b/kdb-bot/src/modules/level/events/level_on_voice_state_update_event.py new file mode 100644 index 0000000000..c9127e0376 --- /dev/null +++ b/kdb-bot/src/modules/level/events/level_on_voice_state_update_event.py @@ -0,0 +1,23 @@ +import discord +from cpl_core.logging import LoggerABC +from cpl_discord.events import OnVoiceStateUpdateABC + +from modules.level.service.level_service import LevelService + + +class LevelOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC): + + def __init__( + self, + logger: LoggerABC, + level: LevelService + ): + OnVoiceStateUpdateABC.__init__(self) + self._logger = logger + self._level = level + + self._logger.info(__name__, f'Module {type(self)} loaded') + + async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState): + self._logger.debug(__name__, f'Module {type(self)} started') + await self._level.check_level(member) diff --git a/kdb-bot/src/modules/level/level_module.py b/kdb-bot/src/modules/level/level_module.py index 760544babf..1943e73cf4 100644 --- a/kdb-bot/src/modules/level/level_module.py +++ b/kdb-bot/src/modules/level/level_module.py @@ -3,10 +3,13 @@ import os from cpl_core.configuration import ConfigurationABC from cpl_core.dependency_injection import ServiceCollectionABC from cpl_core.environment import ApplicationEnvironmentABC +from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum from cpl_discord.service.discord_collection_abc import DiscordCollectionABC from bot_core.abc.module_abc import ModuleABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum +from modules.level.events.level_on_message_event import LevelOnMessageEvent +from modules.level.events.level_on_voice_state_update_event import LevelOnVoiceStateUpdateEvent from modules.level.level_seeder import LevelSeeder from modules.level.service.level_service import LevelService @@ -25,3 +28,6 @@ class LevelModule(ModuleABC): def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): services.add_transient(LevelSeeder) services.add_transient(LevelService) + + self._dc.add_event(DiscordEventTypesEnum.on_message.value, LevelOnMessageEvent) + self._dc.add_event(DiscordEventTypesEnum.on_voice_state_update.value, LevelOnVoiceStateUpdateEvent) diff --git a/kdb-bot/src/modules/level/level_seeder.py b/kdb-bot/src/modules/level/level_seeder.py index e732912653..377bfd2a6d 100644 --- a/kdb-bot/src/modules/level/level_seeder.py +++ b/kdb-bot/src/modules/level/level_seeder.py @@ -18,14 +18,16 @@ class LevelSeeder(DataSeederABC): DataSeederABC.__init__(self) self._logger = logger - self._default_levels = levels.levels.order_by_descending(lambda l: l.min_xp) self._levels = level_repo self._servers = servers self._bot = bot + self._level_header = levels.level_header + self._default_levels = levels.levels.order_by_descending(lambda l: l.min_xp) + async def _create_level(self, level: Level, guild: Guild, server: Server): try: - if guild.roles.where(lambda r: r.name == level.name).count() > 0: + if guild.roles.where(lambda r: r.name == level.name).first_or_default() is not None: return await guild.create_role(name=level.name, colour=Colour(int(level.color, 16)), hoist=False, mentionable=True, permissions=Permissions(level.permissions)) @@ -39,8 +41,8 @@ class LevelSeeder(DataSeederABC): # create levels for guild in self._bot.guilds: created_default = False - if guild.roles.where(lambda r: r.name == '___ Level ___').count() == 0: - await guild.create_role(name='___ Level ___') + if guild.roles.where(lambda r: r.name == self._level_header).first_or_default() is None: + await guild.create_role(name=self._level_header) server = self._servers.find_server_by_discord_id(guild.id) if server is None: @@ -64,7 +66,7 @@ class LevelSeeder(DataSeederABC): if created_default: continue - position_above_levels = guild.roles.where(lambda r: r.name == '~~~ Level ~~~').single().position + position_above_levels = guild.roles.where(lambda r: r.name == self._level_header).single().position for role in guild.roles.order_by_descending(lambda r: r.position): if levels.where(lambda l: l.name == role.name).count() == 0: continue diff --git a/kdb-bot/src/modules/level/service/level_service.py b/kdb-bot/src/modules/level/service/level_service.py index b3d2f664f4..95fbcae623 100644 --- a/kdb-bot/src/modules/level/service/level_service.py +++ b/kdb-bot/src/modules/level/service/level_service.py @@ -1,3 +1,4 @@ +import discord from cpl_core.database.context import DatabaseContextABC from cpl_core.logging import LoggerABC from cpl_discord.container import Guild, Role, Member @@ -6,6 +7,7 @@ from cpl_discord.service import DiscordBotServiceABC from bot_data.model.level import Level from bot_data.model.user import User from bot_data.service.level_repository_service import LevelRepositoryService +from bot_data.service.server_repository_service import ServerRepositoryService from bot_data.service.user_repository_service import UserRepositoryService @@ -17,17 +19,19 @@ class LevelService: db: DatabaseContextABC, levels: LevelRepositoryService, users: UserRepositoryService, + servers: ServerRepositoryService, bot: DiscordBotServiceABC ): self._logger = logger self._db = db self._levels = levels self._users = users + self._servers = servers self._bot = bot def get_level(self, user: User) -> Level: levels = self._levels.get_levels_by_server_id(user.server.server_id).order_by(lambda l: l.min_xp) - return levels.where(lambda l: l.min_xp > user.xp).first() + return levels.where(lambda l: user.xp >= l.min_xp).first() async def set_level(self, user: User): level_names = self._levels.get_levels_by_server_id(user.server.server_id).select(lambda l: l.name) @@ -45,9 +49,22 @@ class LevelService: except Exception as e: self._logger.error(__name__, f'Removing role {role.name} from {member.name} failed!', e) + if level_role in member.roles: + return try: self._logger.debug(__name__, f'Try to add role {level_role.name} to {member.name}') await member.add_roles(level_role) self._logger.info(__name__, f'Add role {level_role.name} to {member.name}') except Exception as e: self._logger.error(__name__, f'Adding role {level_role.name} to {member.name} failed!', e) + + async def check_level(self, member: discord.Member): + if member.bot: + return + + server = self._servers.get_server_by_discord_id(member.guild.id) + user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) + if user is None: + self._logger.warn(__name__, f'User not found {member.guild.name}@{member.name}') + + await self.set_level(user)