Improved permission handling

This commit is contained in:
Sven Heidemann 2021-12-29 20:41:15 +01:00
parent ff247bcec3
commit a8663b8d54
9 changed files with 164 additions and 61 deletions

View File

@ -71,12 +71,10 @@ class Startup(StartupABC):
services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings)) services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings))
# modules # general services
services.add_singleton(ModuleServiceABC, ModuleService) services.add_singleton(ModuleServiceABC, ModuleService)
services.add_singleton(BotServiceABC, BotService) services.add_singleton(BotServiceABC, BotService)
services.add_transient(MessageServiceABC, MessageService) services.add_transient(MessageServiceABC, MessageService)
# general services
services.add_transient(MigrationService) services.add_transient(MigrationService)
# data services # data services
@ -87,14 +85,15 @@ class Startup(StartupABC):
services.add_transient(UserJoinedServerRepositoryABC, UserJoinedServerRepositoryService) services.add_transient(UserJoinedServerRepositoryABC, UserJoinedServerRepositoryService)
services.add_transient(UserJoinedVoiceChannelRepositoryABC, UserJoinedVoiceChannelRepositoryService) services.add_transient(UserJoinedVoiceChannelRepositoryABC, UserJoinedVoiceChannelRepositoryService)
# module services
services.add_singleton(PermissionServiceABC, PermissionService)
# modules # modules
services.add_transient(ModuleABC, Permission)
services.add_transient(ModuleABC, Database) services.add_transient(ModuleABC, Database)
services.add_transient(ModuleABC, Base)
services.add_transient(ModuleABC, BootLog) services.add_transient(ModuleABC, BootLog)
services.add_singleton(ModuleABC, Permission)
# permission module services services.add_singleton(ModuleABC, Base)
services.add_transient(PermissionServiceABC, PermissionService)
# migrations # migrations
services.add_transient(MigrationABC, InitialMigration) services.add_transient(MigrationABC, InitialMigration)

View File

@ -20,6 +20,7 @@ from gismo_data.model.user import User
from gismo_data.model.user_joined_server import UserJoinedServer from gismo_data.model.user_joined_server import UserJoinedServer
from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from modules.base.base_settings import BaseSettings from modules.base.base_settings import BaseSettings
from modules.permission.abc.permission_service_abc import PermissionServiceABC
from modules_core.abc.events.on_member_join_abc import OnMemberJoinABC from modules_core.abc.events.on_member_join_abc import OnMemberJoinABC
from modules_core.abc.events.on_member_remove_abc import OnMemberRemoveABC from modules_core.abc.events.on_member_remove_abc import OnMemberRemoveABC
from modules_core.abc.events.on_message_abc import OnMessageABC from modules_core.abc.events.on_message_abc import OnMessageABC
@ -42,7 +43,8 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
user_joins_vc: UserJoinedVoiceChannelRepositoryABC, user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
bot: BotServiceABC, bot: BotServiceABC,
db: DatabaseContextABC, db: DatabaseContextABC,
messenger: MessageServiceABC messenger: MessageServiceABC,
permission_service: PermissionServiceABC
): ):
self._config = config self._config = config
self._logger = logger self._logger = logger
@ -55,6 +57,7 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
self._bot = bot self._bot = bot
self._db = db self._db = db
self._messenger = messenger self._messenger = messenger
self._permission_service = permission_service
ModuleABC.__init__( ModuleABC.__init__(
self, self,
@ -66,7 +69,7 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
}, },
BaseSettings BaseSettings
) )
self._logger.trace(__name__, f'Module {type(self)} loaded') self._logger.info(__name__, f'Module {type(self)} loaded')
def _get_config(self, g_id: int) -> BaseSettings: def _get_config(self, g_id: int) -> BaseSettings:
return self._config.get_configuration(f'{type(self).__name__}_{g_id}') return self._config.get_configuration(f'{type(self).__name__}_{g_id}')
@ -100,21 +103,14 @@ class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceS
async def _add_if_not_exists_user(self, member: Union[discord.User, discord.Member]): async def _add_if_not_exists_user(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Check if user exists {member}') self._logger.debug(__name__, f'Check if user exists {member}')
# todo: user permission service
settings: BaseSettings = self._get_config() settings: BaseSettings = self._get_config()
await self._messenger.send_dm_message(settings.welcome_message.format(member.guild.name), member) await self._messenger.send_dm_message(settings.welcome_message.format(member.guild.name), member)
for roleId in settings.admin_roles: for admin in self._permission_service.get_admins():
g: discord.Guild = member.guild await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), admin)
role: discord.Role = g.get_role(roleId)
for admin in role.members:
await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), admin)
for roleId in settings.moderator_roles: for moderator in self._permission_service.get_moderators():
g: discord.Guild = member.guild await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), moderator)
role: discord.Role = g.get_role(roleId)
for mod in role.members:
await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), mod)
try: try:
server = self._servers.get_server_by_discord_id(member.guild.id) server = self._servers.get_server_by_discord_id(member.guild.id)

View File

@ -35,7 +35,7 @@ class BootLog(ModuleABC, OnReadyABC):
}, },
BootLogSettings BootLogSettings
) )
self._logger.trace(__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')

View File

@ -57,7 +57,7 @@ class Database(ModuleABC, OnReadyABC):
{ OnReadyABC: 0 }, { OnReadyABC: 0 },
None None
) )
self._logger.trace(__name__, f'Module {type(self)} loaded') self._logger.info(__name__, f'Module {type(self)} loaded')
def _validate_init_time(self): def _validate_init_time(self):
try: try:

View File

@ -1,7 +1,32 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import discord
class PermissionServiceABC(ABC): class PermissionServiceABC(ABC):
@abstractmethod @abstractmethod
def __init__(self): pass def __init__(self): pass
@abstractmethod
def on_ready(self): pass
@abstractmethod
def on_member_update(self, before: discord.Member, after: discord.Member): pass
@abstractmethod
def get_admin_role_ids(self, g_id: int) -> list[int]: pass
@abstractmethod
def get_admin_roles(self, g_id: int) -> list[discord.Role]: pass
@abstractmethod
def get_admins(self, g_id: int) -> list[discord.Member]: pass
@abstractmethod
def get_moderator_role_ids(self, g_id: int) -> list[int]: pass
@abstractmethod
def get_moderator_roles(self, g_id: int) -> list[discord.Role]: pass
@abstractmethod
def get_moderators(self, g_id: int) -> list[discord.Member]: pass

View File

@ -12,7 +12,6 @@ class PermissionSettings(ConfigurationModelABC):
self._admin_roles: list[int] = [] self._admin_roles: list[int] = []
self._moderator_roles: list[int] = [] self._moderator_roles: list[int] = []
@property @property
def admin_roles(self) -> list[int]: def admin_roles(self) -> list[int]:
return self._admin_roles return self._admin_roles

View File

@ -1,41 +1,37 @@
from ctypes import Union
from datetime import datetime
import discord import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from gismo_core.abc.bot_service_abc import BotServiceABC from cpl_core.logging import LoggerABC
from gismo_core.configuration.server_settings import ServerSettings from modules.permission.abc.permission_service_abc import PermissionServiceABC
from gismo_data.abc.client_repository_abc import ClientRepositoryABC from modules.permission.configuration.permission_settings import \
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC PermissionSettings
from gismo_data.abc.user_joined_server_repository_abc import \ from modules_core.abc.events.on_member_update_abc import OnMemberUpdateABC
UserJoinedServerRepositoryABC
from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
from gismo_data.abc.user_repository_abc import UserRepositoryABC
from gismo_data.model.client import Client
from gismo_data.model.known_user import KnownUser
from gismo_data.model.server import Server
from gismo_data.model.user import User
from gismo_data.model.user_joined_server import UserJoinedServer
from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from gismo_data.service.user_repository_service import ServerRepositoryABC
from modules.permission.configuration.permission_settings import PermissionSettings
from modules_core.abc.events.on_ready_abc import OnReadyABC from modules_core.abc.events.on_ready_abc import OnReadyABC
from modules_core.abc.module_abc import ModuleABC from modules_core.abc.module_abc import ModuleABC
class Permission(ModuleABC): class Permission(ModuleABC, OnReadyABC, OnMemberUpdateABC):
def __init__( def __init__(
self, self,
logger: LoggerABC, logger: LoggerABC,
permission_service: PermissionServiceABC
): ):
self._logger = logger self._logger = logger
self._permission_service = permission_service
ModuleABC.__init__( ModuleABC.__init__(
self, self,
{ OnReadyABC: 0 }, { OnReadyABC: 1, OnMemberUpdateABC: 0 },
PermissionSettings PermissionSettings
) )
self._logger.trace(__name__, f'Module {type(self)} loaded') self._logger.info(__name__, f'Module {type(self)} loaded')
async def on_ready(self):
self._logger.debug(__name__, f'Module {type(self)} started')
self._permission_service.on_ready()
async def on_member_update(self, before: discord.Member, after: discord.Member):
self._logger.debug(__name__, f'Module {type(self)} started')
if before.roles != after.roles:
self._permission_service.on_member_update(before, after)

View File

@ -1,4 +1,88 @@
class PermissionService: import discord
from cpl_core.logging import LoggerABC
from cpl_core.configuration import ConfigurationABC
from gismo_core.abc.bot_service_abc import BotServiceABC
from modules.permission.abc.permission_service_abc import PermissionServiceABC
from modules.permission.configuration.permission_settings import PermissionSettings
def __init__(self):
pass class PermissionService(PermissionServiceABC):
def __init__(self, logger: LoggerABC, bot: BotServiceABC, config: ConfigurationABC):
PermissionServiceABC.__init__(self)
self._logger = logger
self._bot = bot
self._config = config
self._admin_role_ids: dict[str, list[int]] = {}
self._admin_roles: dict[list[discord.Role]] = {}
self._admins: dict[list[discord.Member]] = {}
self._moderator_role_ids: dict[list[int]] = {}
self._moderator_roles: dict[list[discord.Role]] = {}
self._moderators: dict[list[discord.Member]] = {}
def on_ready(self):
for guild in self._bot.guilds:
guild: discord.Guild = guild
settings: PermissionSettings = self._config.get_configuration(f'Permission_{guild.id}')
if settings is None:
self._logger.error(__name__, 'Permission settings not found')
return
self._admin_role_ids[guild.id] = settings.admin_roles
self._admin_roles[guild.id] = []
self._admins[guild.id] = []
self._moderator_role_ids[guild.id] = settings.moderator_roles
self._moderator_roles[guild.id] = []
self._moderators[guild.id] = []
for role in guild.roles:
role: discord.Role = role
if role.id in self._admin_role_ids:
self._admin_roles[guild.id].append(role)
for member in role.members:
self._admins[guild.id].append(member)
if role.id in self._moderator_role_ids:
self._moderator_roles[guild.id].append(role)
for member in role.members:
self._moderators[guild.id].append(member)
def on_member_update(self, before: discord.Member, after: discord.Member):
g_id = after.guild.id
if before in self._admin_roles[g_id] and after not in self._admin_roles[g_id]:
self._admins[g_id].remove(after)
elif before not in self._admin_roles[g_id] and after in self._admin_roles[g_id]:
self._admins[g_id].append(after)
if before in self._moderator_roles[g_id] and after not in self._moderator_roles[g_id]:
self._moderators[g_id].remove(after)
elif before not in self._moderator_roles[g_id] and after in self._moderator_roles[g_id]:
self._moderators[g_id].append(after)
def get_admin_role_ids(self, g_id: int) -> list[int]:
return self._admin_role_ids[g_id]
def get_admin_roles(self, g_id: int) -> list[discord.Role]:
return self._admin_roles[g_id]
def get_admins(self, g_id: int) -> list[discord.Member]:
return self._admins[g_id]
def get_moderator_role_ids(self, g_id: int) -> list[int]:
return self._moderator_role_ids[g_id]
def get_moderator_roles(self, g_id: int) -> list[discord.Role]:
return self._moderator_roles[g_id]
def get_moderators(self, g_id: int) -> list[discord.Member]:
return self._moderators[g_id]

View File

@ -90,7 +90,7 @@ class ModuleService(ModuleServiceABC, commands.Cog, metaclass=_MetaCogABC):
settings: ConfigurationModelABC = module.settings_type() settings: ConfigurationModelABC = module.settings_type()
settings.from_dict(json_cfg[id]) settings.from_dict(json_cfg[id])
self._config.add_configuration(f'{type(module).__name__}_{id}', settings) self._config.add_configuration(f'{type(module).__name__}_{id}', settings)
self._logger.debug(__name__, f'Added config: {type(module).__name__}_{id}') self._logger.info(__name__, f'Added config: {type(module).__name__}_{id}')
modules.append(module) modules.append(module)
@ -103,14 +103,18 @@ class ModuleService(ModuleServiceABC, commands.Cog, metaclass=_MetaCogABC):
if modules.count() < 1: if modules.count() < 1:
self._logger.debug(__name__, f'Stopped {event} modules') self._logger.debug(__name__, f'Stopped {event} modules')
return return
func_name = String.convert_to_snake_case(event.__name__.split('ABC')[0]) try:
for module in modules: func_name = String.convert_to_snake_case(event.__name__.split('ABC')[0])
func = getattr(module, func_name) for module in modules:
await func(*args) self._logger.trace(__name__, f'Start {type(module)} module')
if not module.success: func = getattr(module, func_name)
self._logger.debug(__name__, f'Stopped propagation for {event} from {type(module)}') await func(*args)
break if not module.success:
self._logger.debug(__name__, f'Stopped propagation for {event} from {type(module)}')
break
except Exception as e:
self._logger.error(__name__, f'Start {event} modules failed', e)
self._logger.debug(__name__, f'Stopped {event} modules') self._logger.debug(__name__, f'Stopped {event} modules')