Added logic to handle level by xp #25

This commit is contained in:
Sven Heidemann 2022-11-06 21:34:58 +01:00
parent 8aee72856c
commit 164671a07c
9 changed files with 138 additions and 34 deletions

View File

@ -63,7 +63,7 @@ class LevelRepositoryService(LevelRepositoryABC):
def get_levels_by_server_id(self, server_id: int) -> List[Level]: def get_levels_by_server_id(self, server_id: int) -> List[Level]:
levels = List(Level) levels = List(Level)
self._logger.trace(__name__, f'Send SQL command: {Level.get_select_by_server_id_string(server_id)}') 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: for result in results:
self._logger.trace(__name__, f'Get level with id {result[0]}') self._logger.trace(__name__, f'Get level with id {result[0]}')

View File

@ -13,14 +13,20 @@ class LevelSettings(ConfigurationModelABC):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self)
self._levels = List(Level) self._levels = List(Level)
self._level_header = ''
@property @property
def levels(self) -> List[Level]: def levels(self) -> List[Level]:
return self._levels return self._levels
@property
def level_header(self) -> str:
return self._level_header
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
for level in settings: self._level_header = settings['LevelHeader']
for level in settings['Levels']:
self._levels.append(Level( self._levels.append(Level(
level['Name'], level['Name'],
level['Color'], level['Color'],

View File

@ -1,5 +1,7 @@
{ {
"Level": [ "Level": {
"LevelHeader": "~~~ Level ~~~",
"Levels": [
{ {
"Name": "Newbie", "Name": "Newbie",
"Color": "0x1abc9c", "Color": "0x1abc9c",
@ -25,4 +27,5 @@
"Permissions": 1089042120513 "Permissions": 1089042120513
} }
] ]
}
} }

View File

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

View File

@ -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)

View File

@ -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)

View File

@ -3,10 +3,13 @@ import os
from cpl_core.configuration import ConfigurationABC from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceCollectionABC from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC 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 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 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.level_seeder import LevelSeeder
from modules.level.service.level_service import LevelService from modules.level.service.level_service import LevelService
@ -25,3 +28,6 @@ class LevelModule(ModuleABC):
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_transient(LevelSeeder) services.add_transient(LevelSeeder)
services.add_transient(LevelService) services.add_transient(LevelService)
self._dc.add_event(DiscordEventTypesEnum.on_message.value, LevelOnMessageEvent)
self._dc.add_event(DiscordEventTypesEnum.on_voice_state_update.value, LevelOnVoiceStateUpdateEvent)

View File

@ -18,14 +18,16 @@ class LevelSeeder(DataSeederABC):
DataSeederABC.__init__(self) DataSeederABC.__init__(self)
self._logger = logger self._logger = logger
self._default_levels = levels.levels.order_by_descending(lambda l: l.min_xp)
self._levels = level_repo self._levels = level_repo
self._servers = servers self._servers = servers
self._bot = bot 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): async def _create_level(self, level: Level, guild: Guild, server: Server):
try: 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 return
await guild.create_role(name=level.name, colour=Colour(int(level.color, 16)), hoist=False, mentionable=True, permissions=Permissions(level.permissions)) 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 # create levels
for guild in self._bot.guilds: for guild in self._bot.guilds:
created_default = False created_default = False
if guild.roles.where(lambda r: r.name == '___ Level ___').count() == 0: if guild.roles.where(lambda r: r.name == self._level_header).first_or_default() is None:
await guild.create_role(name='___ Level ___') await guild.create_role(name=self._level_header)
server = self._servers.find_server_by_discord_id(guild.id) server = self._servers.find_server_by_discord_id(guild.id)
if server is None: if server is None:
@ -64,7 +66,7 @@ class LevelSeeder(DataSeederABC):
if created_default: if created_default:
continue 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): for role in guild.roles.order_by_descending(lambda r: r.position):
if levels.where(lambda l: l.name == role.name).count() == 0: if levels.where(lambda l: l.name == role.name).count() == 0:
continue continue

View File

@ -1,3 +1,4 @@
import discord
from cpl_core.database.context import DatabaseContextABC from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC from cpl_core.logging import LoggerABC
from cpl_discord.container import Guild, Role, Member 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.level import Level
from bot_data.model.user import User from bot_data.model.user import User
from bot_data.service.level_repository_service import LevelRepositoryService 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 from bot_data.service.user_repository_service import UserRepositoryService
@ -17,17 +19,19 @@ class LevelService:
db: DatabaseContextABC, db: DatabaseContextABC,
levels: LevelRepositoryService, levels: LevelRepositoryService,
users: UserRepositoryService, users: UserRepositoryService,
servers: ServerRepositoryService,
bot: DiscordBotServiceABC bot: DiscordBotServiceABC
): ):
self._logger = logger self._logger = logger
self._db = db self._db = db
self._levels = levels self._levels = levels
self._users = users self._users = users
self._servers = servers
self._bot = bot self._bot = bot
def get_level(self, user: User) -> Level: 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) 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): 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) 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: except Exception as e:
self._logger.error(__name__, f'Removing role {role.name} from {member.name} failed!', e) self._logger.error(__name__, f'Removing role {role.name} from {member.name} failed!', e)
if level_role in member.roles:
return
try: try:
self._logger.debug(__name__, f'Try to add role {level_role.name} to {member.name}') self._logger.debug(__name__, f'Try to add role {level_role.name} to {member.name}')
await member.add_roles(level_role) await member.add_roles(level_role)
self._logger.info(__name__, f'Add role {level_role.name} to {member.name}') self._logger.info(__name__, f'Add role {level_role.name} to {member.name}')
except Exception as e: except Exception as e:
self._logger.error(__name__, f'Adding role {level_role.name} to {member.name} failed!', 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)