Merge pull request '#334_feature_flags_in_wi' (#335) from #334_feature_flags_in_wi into 1.1.0
Reviewed-on: sh-edraft.de/kd_discord_bot#335 Reviewed-by: edraft-dev <dev.sven.heidemann@sh-edraft.de> Closes #334
This commit is contained in:
		 Submodule kdb-bot/src/bot/config updated: 359f9c38c3...20adf415f9
									
								
							@@ -31,10 +31,10 @@ class Program:
 | 
			
		||||
            .use_extension(StartupDiscordExtension)
 | 
			
		||||
            .use_extension(StartupModuleExtension)
 | 
			
		||||
            .use_extension(StartupMigrationExtension)
 | 
			
		||||
            .use_extension(DatabaseExtension)
 | 
			
		||||
            .use_extension(ConfigExtension)
 | 
			
		||||
            .use_extension(InitBotExtension)
 | 
			
		||||
            .use_extension(BootLogExtension)
 | 
			
		||||
            .use_extension(DatabaseExtension)
 | 
			
		||||
            .use_extension(AppApiExtension)
 | 
			
		||||
            .use_extension(CoreExtension)
 | 
			
		||||
            .use_startup(Startup)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from bot_data.migration.api_key_migration import ApiKeyMigration
 | 
			
		||||
from bot_data.migration.api_migration import ApiMigration
 | 
			
		||||
from bot_data.migration.auto_role_fix1_migration import AutoRoleFix1Migration
 | 
			
		||||
from bot_data.migration.auto_role_migration import AutoRoleMigration
 | 
			
		||||
from bot_data.migration.config_feature_flags_migration import ConfigFeatureFlagsMigration
 | 
			
		||||
from bot_data.migration.config_migration import ConfigMigration
 | 
			
		||||
from bot_data.migration.db_history_migration import DBHistoryMigration
 | 
			
		||||
from bot_data.migration.initial_migration import InitialMigration
 | 
			
		||||
@@ -46,3 +47,4 @@ class StartupMigrationExtension(StartupExtensionABC):
 | 
			
		||||
        services.add_transient(MigrationABC, DBHistoryMigration)  # 06.03.2023 #246 - 1.0.0
 | 
			
		||||
        services.add_transient(MigrationABC, AchievementsMigration)  # 14.06.2023 #268 - 1.1.0
 | 
			
		||||
        services.add_transient(MigrationABC, ConfigMigration)  # 19.07.2023 #127 - 1.1.0
 | 
			
		||||
        services.add_transient(MigrationABC, ConfigFeatureFlagsMigration)  # 15.08.2023 #334 - 1.1.0
 | 
			
		||||
 
 | 
			
		||||
@@ -5,18 +5,17 @@ class FeatureFlagsEnum(Enum):
 | 
			
		||||
    # modules
 | 
			
		||||
    achievements_module = "AchievementsModule"
 | 
			
		||||
    api_module = "ApiModule"
 | 
			
		||||
    admin_module = "AdminModule"
 | 
			
		||||
    auto_role_module = "AutoRoleModule"
 | 
			
		||||
    base_module = "BaseModule"
 | 
			
		||||
    boot_log_module = "BootLogModule"
 | 
			
		||||
    core_module = "CoreModule"
 | 
			
		||||
    core_extension_module = "CoreExtensionModule"
 | 
			
		||||
    config_module = "ConfigModule"
 | 
			
		||||
    data_module = "DataModule"
 | 
			
		||||
    database_module = "DatabaseModule"
 | 
			
		||||
    level_module = "LevelModule"
 | 
			
		||||
    moderator_module = "ModeratorModule"
 | 
			
		||||
    permission_module = "PermissionModule"
 | 
			
		||||
    config_module = "ConfigModule"
 | 
			
		||||
    # features
 | 
			
		||||
    api_only = "ApiOnly"
 | 
			
		||||
    presence = "Presence"
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
 | 
			
		||||
        # modules
 | 
			
		||||
        FeatureFlagsEnum.achievements_module.value: False,  # 14.06.2023 #268
 | 
			
		||||
        FeatureFlagsEnum.api_module.value: False,  # 13.10.2022 #70
 | 
			
		||||
        FeatureFlagsEnum.admin_module.value: False,  # 02.10.2022 #48
 | 
			
		||||
        FeatureFlagsEnum.auto_role_module.value: True,  # 03.10.2022 #54
 | 
			
		||||
        FeatureFlagsEnum.auto_role_module.value: False,  # 03.10.2022 #54
 | 
			
		||||
        FeatureFlagsEnum.base_module.value: True,  # 02.10.2022 #48
 | 
			
		||||
        FeatureFlagsEnum.boot_log_module.value: True,  # 02.10.2022 #48
 | 
			
		||||
        FeatureFlagsEnum.core_module.value: True,  # 03.10.2022 #56
 | 
			
		||||
@@ -34,6 +33,17 @@ class FeatureFlagsSettings(ConfigurationModelABC):
 | 
			
		||||
        for flag in [f.value for f in FeatureFlagsEnum]:
 | 
			
		||||
            self._load_flag(kwargs, FeatureFlagsEnum(flag))
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_flag_from_dict(cls, flags: dict, key: FeatureFlagsEnum) -> bool:
 | 
			
		||||
        def get_flag():
 | 
			
		||||
            if key.value not in cls._flags:
 | 
			
		||||
                return False
 | 
			
		||||
            return cls._flags[key.value]
 | 
			
		||||
 | 
			
		||||
        if key.value not in flags:
 | 
			
		||||
            return get_flag()
 | 
			
		||||
        return flags[key.value]
 | 
			
		||||
 | 
			
		||||
    def get_flag(self, key: FeatureFlagsEnum) -> bool:
 | 
			
		||||
        if key.value not in self._flags:
 | 
			
		||||
            return False
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.events.core_on_ready_event import CoreOnReadyEvent
 | 
			
		||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
 | 
			
		||||
from bot_core.service.client_utils_service import ClientUtilsService
 | 
			
		||||
from bot_core.service.config_service import ConfigService
 | 
			
		||||
from bot_core.service.data_integrity_service import DataIntegrityService
 | 
			
		||||
from bot_core.service.message_service import MessageService
 | 
			
		||||
 | 
			
		||||
@@ -23,6 +24,7 @@ class CoreModule(ModuleABC):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
 | 
			
		||||
        services.add_transient(ConfigService)
 | 
			
		||||
        services.add_transient(MessageServiceABC, MessageService)
 | 
			
		||||
        services.add_transient(ClientUtilsABC, ClientUtilsService)
 | 
			
		||||
        services.add_transient(DataIntegrityService)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								kdb-bot/src/bot_core/service/config_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								kdb-bot/src/bot_core/service/config_service.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
 | 
			
		||||
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
 | 
			
		||||
from bot_data.model.server import Server
 | 
			
		||||
from bot_data.model.technician_config import TechnicianConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConfigService:
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        technician_config_repo: TechnicianConfigRepositoryABC,
 | 
			
		||||
        server_config_repo: ServerConfigRepositoryABC,
 | 
			
		||||
    ):
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._technician_config_repo = technician_config_repo
 | 
			
		||||
        self._server_config_repo = server_config_repo
 | 
			
		||||
 | 
			
		||||
    def reload_technician_config(self):
 | 
			
		||||
        technician_config = self._technician_config_repo.get_technician_config()
 | 
			
		||||
        self._config.add_configuration(TechnicianConfig, technician_config)
 | 
			
		||||
        self._config.add_configuration(FeatureFlagsSettings, FeatureFlagsSettings(**technician_config.feature_flags))
 | 
			
		||||
 | 
			
		||||
    def reload_server_config(self, server: Server):
 | 
			
		||||
        server_config = self._server_config_repo.get_server_config_by_server(server.id)
 | 
			
		||||
        self._config.add_configuration(
 | 
			
		||||
            f"{type(server_config).__name__}_{server_config.server.discord_id}", server_config
 | 
			
		||||
        )
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
from bot_core.logging.database_logger import DatabaseLogger
 | 
			
		||||
from bot_data.abc.migration_abc import MigrationABC
 | 
			
		||||
from bot_data.db_context import DBContext
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConfigFeatureFlagsMigration(MigrationABC):
 | 
			
		||||
    name = "1.1.0_ConfigFeatureFlagsMigration"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, logger: DatabaseLogger, db: DBContext):
 | 
			
		||||
        MigrationABC.__init__(self)
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._db = db
 | 
			
		||||
        self._cursor = db.cursor
 | 
			
		||||
 | 
			
		||||
    def upgrade(self):
 | 
			
		||||
        self._logger.debug(__name__, "Running upgrade")
 | 
			
		||||
 | 
			
		||||
        self._cursor.execute(
 | 
			
		||||
            str(
 | 
			
		||||
                """ALTER TABLE CFG_Technician ADD FeatureFlags JSON NULL DEFAULT JSON_OBJECT() AFTER CacheMaxMessages;"""
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self._cursor.execute(
 | 
			
		||||
            str(
 | 
			
		||||
                """ALTER TABLE CFG_Server ADD FeatureFlags JSON NULL DEFAULT JSON_OBJECT() AFTER LoginMessageChannelId;"""
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def downgrade(self):
 | 
			
		||||
        self._logger.debug(__name__, "Running downgrade")
 | 
			
		||||
        self._cursor.execute("ALTER TABLE CFG_Technician DROP COLUMN FeatureFlags;")
 | 
			
		||||
        self._cursor.execute("ALTER TABLE CFG_Server DROP COLUMN FeatureFlags;")
 | 
			
		||||
@@ -143,6 +143,8 @@ class ConfigMigration(MigrationABC):
 | 
			
		||||
 | 
			
		||||
    def downgrade(self):
 | 
			
		||||
        self._logger.debug(__name__, "Running downgrade")
 | 
			
		||||
        self._server_downgrade()
 | 
			
		||||
        self._technician_downgrade()
 | 
			
		||||
 | 
			
		||||
    def _server_downgrade(self):
 | 
			
		||||
        self._cursor.execute("DROP TABLE `CFG_Server`;")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,11 @@
 | 
			
		||||
import json
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from cpl_core.configuration import ConfigurationModelABC
 | 
			
		||||
from cpl_core.database import TableABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_data.model.server import Server
 | 
			
		||||
from bot_data.model.server_team_role_ids_config import ServerTeamRoleIdsConfig
 | 
			
		||||
 | 
			
		||||
@@ -24,6 +26,7 @@ class ServerConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
        help_voice_channel_id: int,
 | 
			
		||||
        team_channel_id: int,
 | 
			
		||||
        login_message_channel_id: int,
 | 
			
		||||
        feature_flags: dict[FeatureFlagsEnum],
 | 
			
		||||
        server: Server,
 | 
			
		||||
        afk_channel_ids: List[int],
 | 
			
		||||
        team_role_ids: List[ServerTeamRoleIdsConfig],
 | 
			
		||||
@@ -45,6 +48,7 @@ class ServerConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
        self._help_voice_channel_id = help_voice_channel_id
 | 
			
		||||
        self._team_channel_id = team_channel_id
 | 
			
		||||
        self._login_message_channel_id = login_message_channel_id
 | 
			
		||||
        self._feature_flags = feature_flags
 | 
			
		||||
        self._server = server
 | 
			
		||||
        self._afk_channel_ids = afk_channel_ids
 | 
			
		||||
        self._team_role_ids = team_role_ids
 | 
			
		||||
@@ -161,6 +165,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
    def login_message_channel_id(self, value: int):
 | 
			
		||||
        self._login_message_channel_id = value
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def feature_flags(self) -> dict[FeatureFlagsEnum]:
 | 
			
		||||
        return self._feature_flags
 | 
			
		||||
 | 
			
		||||
    @feature_flags.setter
 | 
			
		||||
    def feature_flags(self, value: dict[FeatureFlagsEnum]):
 | 
			
		||||
        self._feature_flags = value
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def afk_channel_ids(self) -> List[int]:
 | 
			
		||||
        return self._afk_channel_ids
 | 
			
		||||
@@ -225,6 +237,7 @@ class ServerConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
                    `HelpVoiceChannelId`,
 | 
			
		||||
                    `TeamChannelId`,
 | 
			
		||||
                    `LoginMessageChannelId`,
 | 
			
		||||
                    `FeatureFlags`,
 | 
			
		||||
                    `ServerId`
 | 
			
		||||
                ) VALUES (
 | 
			
		||||
                    {self._message_delete_timer},
 | 
			
		||||
@@ -240,6 +253,7 @@ class ServerConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
                    {self._help_voice_channel_id},
 | 
			
		||||
                    {self._team_channel_id},
 | 
			
		||||
                    {self._login_message_channel_id},
 | 
			
		||||
                    '{json.dumps(self._feature_flags)}',
 | 
			
		||||
                    {self._server.id}
 | 
			
		||||
                );
 | 
			
		||||
            """
 | 
			
		||||
@@ -263,6 +277,7 @@ class ServerConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
                `HelpVoiceChannelId` = {self._help_voice_channel_id},
 | 
			
		||||
                `TeamChannelId` = {self._team_channel_id},
 | 
			
		||||
                `LoginMessageChannelId` = {self._login_message_channel_id},
 | 
			
		||||
                `FeatureFlags` = '{json.dumps(self._feature_flags)}',
 | 
			
		||||
                `ServerId` = {self._server.id}
 | 
			
		||||
                WHERE `Id` = {self._id};
 | 
			
		||||
            """
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ class ServerConfigHistory(HistoryTableABC):
 | 
			
		||||
        help_voice_channel_id: int,
 | 
			
		||||
        team_channel_id: int,
 | 
			
		||||
        login_message_channel_id: int,
 | 
			
		||||
        feature_flags: dict[str],
 | 
			
		||||
        server_id: int,
 | 
			
		||||
        deleted: bool,
 | 
			
		||||
        date_from: str,
 | 
			
		||||
@@ -39,6 +40,7 @@ class ServerConfigHistory(HistoryTableABC):
 | 
			
		||||
        self._help_voice_channel_id = help_voice_channel_id
 | 
			
		||||
        self._team_channel_id = team_channel_id
 | 
			
		||||
        self._login_message_channel_id = login_message_channel_id
 | 
			
		||||
        self._feature_flags = feature_flags
 | 
			
		||||
        self._server_id = server_id
 | 
			
		||||
 | 
			
		||||
        self._deleted = deleted
 | 
			
		||||
@@ -97,6 +99,10 @@ class ServerConfigHistory(HistoryTableABC):
 | 
			
		||||
    def login_message_channel_id(self) -> int:
 | 
			
		||||
        return self._login_message_channel_id
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def feature_flags(self) -> dict[str]:
 | 
			
		||||
        return self._feature_flags
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def server_id(self) -> int:
 | 
			
		||||
        return self._server_id
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
import json
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from cpl_core.configuration import ConfigurationModelABC
 | 
			
		||||
from cpl_core.database import TableABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TechnicianConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
@@ -12,6 +15,7 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
        wait_for_restart: int,
 | 
			
		||||
        wait_for_shutdown: int,
 | 
			
		||||
        cache_max_messages: int,
 | 
			
		||||
        feature_flags: dict[FeatureFlagsEnum],
 | 
			
		||||
        technician_ids: List[int],
 | 
			
		||||
        ping_urls: List[str],
 | 
			
		||||
        created_at: datetime = None,
 | 
			
		||||
@@ -23,6 +27,7 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
        self._wait_for_restart = wait_for_restart
 | 
			
		||||
        self._wait_for_shutdown = wait_for_shutdown
 | 
			
		||||
        self._cache_max_messages = cache_max_messages
 | 
			
		||||
        self._feature_flags = feature_flags
 | 
			
		||||
        self._technician_ids = technician_ids
 | 
			
		||||
        self._ping_urls = ping_urls
 | 
			
		||||
 | 
			
		||||
@@ -66,6 +71,14 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
    def cache_max_messages(self, value: int):
 | 
			
		||||
        self._cache_max_messages = value
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def feature_flags(self) -> dict[FeatureFlagsEnum]:
 | 
			
		||||
        return self._feature_flags
 | 
			
		||||
 | 
			
		||||
    @feature_flags.setter
 | 
			
		||||
    def feature_flags(self, value: dict[FeatureFlagsEnum]):
 | 
			
		||||
        self._feature_flags = value
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def technician_ids(self) -> List[int]:
 | 
			
		||||
        return self._technician_ids
 | 
			
		||||
@@ -104,12 +117,13 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
        return str(
 | 
			
		||||
            f"""
 | 
			
		||||
                INSERT INTO `CFG_Technician` (
 | 
			
		||||
                    `HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`
 | 
			
		||||
                    `HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`, `FeatureFlags`
 | 
			
		||||
                ) VALUES (
 | 
			
		||||
                    '{self._help_command_reference_url}',
 | 
			
		||||
                    {self._wait_for_restart},
 | 
			
		||||
                    {self._wait_for_shutdown},
 | 
			
		||||
                    {self._cache_max_messages}
 | 
			
		||||
                    {self._cache_max_messages},
 | 
			
		||||
                    '{json.dumps(self._feature_flags)}'
 | 
			
		||||
                );
 | 
			
		||||
            """
 | 
			
		||||
        )
 | 
			
		||||
@@ -122,7 +136,8 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
 | 
			
		||||
                SET `HelpCommandReferenceUrl` = '{self._help_command_reference_url}',
 | 
			
		||||
                `WaitForRestart` = {self._wait_for_restart},
 | 
			
		||||
                `WaitForShutdown` = {self._wait_for_shutdown},
 | 
			
		||||
                `CacheMaxMessages` = {self._cache_max_messages}
 | 
			
		||||
                `CacheMaxMessages` = {self._cache_max_messages},
 | 
			
		||||
                `FeatureFlags` = '{json.dumps(self._feature_flags)}'
 | 
			
		||||
                WHERE `Id` = {self._id};
 | 
			
		||||
            """
 | 
			
		||||
        )
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
@@ -62,11 +64,12 @@ class ServerConfigRepositoryService(ServerConfigRepositoryABC):
 | 
			
		||||
            result[11],
 | 
			
		||||
            result[12],
 | 
			
		||||
            result[13],
 | 
			
		||||
            self._servers.get_server_by_id(result[14]),
 | 
			
		||||
            self._get_afk_channel_ids(result[14]),
 | 
			
		||||
            self._get_team_role_ids(result[14]),
 | 
			
		||||
            result[15],
 | 
			
		||||
            json.loads(result[14]),
 | 
			
		||||
            self._servers.get_server_by_id(result[15]),
 | 
			
		||||
            self._get_afk_channel_ids(result[15]),
 | 
			
		||||
            self._get_team_role_ids(result[15]),
 | 
			
		||||
            result[16],
 | 
			
		||||
            result[17],
 | 
			
		||||
            id=result[0],
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,7 @@ class ServerConfigSeeder(DataSeederABC):
 | 
			
		||||
                    guild.system_channel.id,
 | 
			
		||||
                    guild.system_channel.id,
 | 
			
		||||
                    guild.system_channel.id,
 | 
			
		||||
                    {},
 | 
			
		||||
                    server,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
@@ -41,10 +43,11 @@ class TechnicianConfigRepositoryService(TechnicianConfigRepositoryABC):
 | 
			
		||||
            result[2],
 | 
			
		||||
            result[3],
 | 
			
		||||
            result[4],
 | 
			
		||||
            json.loads(result[5]),
 | 
			
		||||
            self._get_technician_ids(),
 | 
			
		||||
            self._get_technician_ping_urls(),
 | 
			
		||||
            result[5],
 | 
			
		||||
            result[6],
 | 
			
		||||
            result[7],
 | 
			
		||||
            id=result[0],
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ class TechnicianConfigSeeder(DataSeederABC):
 | 
			
		||||
                8,
 | 
			
		||||
                8,
 | 
			
		||||
                1000000,
 | 
			
		||||
                {},
 | 
			
		||||
                List(int, [240160344557879316]),
 | 
			
		||||
                List(str, ["www.google.com", "www.sh-edraft.de", "www.keksdose-gaming.de"]),
 | 
			
		||||
            )
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from cpl_query.extension import List
 | 
			
		||||
from bot_api.exception.service_error_code_enum import ServiceErrorCode
 | 
			
		||||
from bot_api.exception.service_exception import ServiceException
 | 
			
		||||
from bot_api.route.route import Route
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_data.model.auth_role_enum import AuthRoleEnum
 | 
			
		||||
from bot_data.model.auth_user import AuthUser
 | 
			
		||||
from bot_data.model.auto_role import AutoRole
 | 
			
		||||
@@ -17,6 +18,7 @@ from bot_data.model.client import Client
 | 
			
		||||
from bot_data.model.known_user import KnownUser
 | 
			
		||||
from bot_data.model.level import Level
 | 
			
		||||
from bot_data.model.server import Server
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from bot_data.model.user import User
 | 
			
		||||
from bot_data.model.user_joined_game_server import UserJoinedGameServer
 | 
			
		||||
from bot_data.model.user_joined_server import UserJoinedServer
 | 
			
		||||
@@ -66,8 +68,12 @@ class QueryABC(ObjectType):
 | 
			
		||||
        self.set_field(f"{name}s", wrapper)
 | 
			
		||||
        self.set_field(f"{name}Count", lambda *args: wrapper(*args).count())
 | 
			
		||||
 | 
			
		||||
    @ServiceProviderABC.inject
 | 
			
		||||
    def _can_user_see_element(self, user: AuthUser, element: T, services: ServiceProviderABC) -> bool:
 | 
			
		||||
    def _can_user_see_element(self, user: AuthUser, element: T) -> bool:
 | 
			
		||||
        @ServiceProviderABC.inject
 | 
			
		||||
        def get_services(services: ServiceProviderABC) -> ServiceProviderABC:
 | 
			
		||||
            return services
 | 
			
		||||
 | 
			
		||||
        services = get_services()
 | 
			
		||||
        permissions: PermissionService = services.get_service(PermissionService)
 | 
			
		||||
        bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
 | 
			
		||||
 | 
			
		||||
@@ -158,6 +164,24 @@ class QueryABC(ObjectType):
 | 
			
		||||
                    access = True
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
        elif type(element) == ServerConfig:
 | 
			
		||||
            for u in user.users:
 | 
			
		||||
                u: User = u
 | 
			
		||||
                guild = bot.get_guild(u.server.discord_id)
 | 
			
		||||
                member = guild.get_member(u.discord_id)
 | 
			
		||||
                if permissions.is_member_technician(member):
 | 
			
		||||
                    access = True
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
        elif type(element) == dict and "key" in element and element["key"] in [e.value for e in FeatureFlagsEnum]:
 | 
			
		||||
            for u in user.users:
 | 
			
		||||
                u: User = u
 | 
			
		||||
                guild = bot.get_guild(u.server.discord_id)
 | 
			
		||||
                member = guild.get_member(u.discord_id)
 | 
			
		||||
                if permissions.is_member_technician(member):
 | 
			
		||||
                    access = True
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
        return access
 | 
			
		||||
 | 
			
		||||
    @ServiceProviderABC.inject
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								kdb-bot/src/bot_graphql/model/featureFlags.gql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								kdb-bot/src/bot_graphql/model/featureFlags.gql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
type FeatureFlag {
 | 
			
		||||
    key: String
 | 
			
		||||
    value: Boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input FeatureFlagInput {
 | 
			
		||||
    key: String
 | 
			
		||||
    value: Boolean
 | 
			
		||||
}
 | 
			
		||||
@@ -40,4 +40,5 @@ type Query {
 | 
			
		||||
    technicianConfig: TechnicianConfig
 | 
			
		||||
 | 
			
		||||
    guilds(filter: GuildFilter): [Guild]
 | 
			
		||||
    possibleFeatureFlags: [String]
 | 
			
		||||
}
 | 
			
		||||
@@ -13,6 +13,8 @@ type ServerConfig implements TableWithHistoryQuery {
 | 
			
		||||
    helpVoiceChannelId: String
 | 
			
		||||
    teamChannelId: String
 | 
			
		||||
    loginMessageChannelId: String
 | 
			
		||||
    featureFlagCount: Int
 | 
			
		||||
    featureFlags: [FeatureFlag]
 | 
			
		||||
 | 
			
		||||
    afkChannelIds: [String]
 | 
			
		||||
    moderatorRoleIds: [String]
 | 
			
		||||
@@ -41,6 +43,8 @@ type ServerConfigHistory implements HistoryTableQuery {
 | 
			
		||||
    helpVoiceChannelId: String
 | 
			
		||||
    teamChannelId: String
 | 
			
		||||
    loginMessageChannelId: String
 | 
			
		||||
    featureFlagCount: Int
 | 
			
		||||
    featureFlags: [FeatureFlag]
 | 
			
		||||
 | 
			
		||||
    serverId: ID
 | 
			
		||||
 | 
			
		||||
@@ -87,6 +91,7 @@ input ServerConfigInput {
 | 
			
		||||
    helpVoiceChannelId: String
 | 
			
		||||
    teamChannelId: String
 | 
			
		||||
    loginMessageChannelId: String
 | 
			
		||||
    featureFlags: [FeatureFlagInput]
 | 
			
		||||
 | 
			
		||||
    afkChannelIds: [String]
 | 
			
		||||
    moderatorRoleIds: [String]
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ type TechnicianConfig implements TableWithHistoryQuery {
 | 
			
		||||
    waitForRestart: Int
 | 
			
		||||
    waitForShutdown: Int
 | 
			
		||||
    cacheMaxMessages: Int
 | 
			
		||||
    featureFlagCount: Int
 | 
			
		||||
    featureFlags: [FeatureFlag]
 | 
			
		||||
    pingURLs: [String]
 | 
			
		||||
    technicianIds: [String]
 | 
			
		||||
 | 
			
		||||
@@ -21,6 +23,8 @@ type TechnicianConfigHistory implements HistoryTableQuery {
 | 
			
		||||
    waitForRestart: Int
 | 
			
		||||
    waitForShutdown: Int
 | 
			
		||||
    cacheMaxMessages: Int
 | 
			
		||||
    featureFlagCount: Int
 | 
			
		||||
    featureFlags: [FeatureFlag]
 | 
			
		||||
 | 
			
		||||
    deleted: Boolean
 | 
			
		||||
    dateFrom: String
 | 
			
		||||
@@ -55,6 +59,7 @@ input TechnicianConfigInput {
 | 
			
		||||
    waitForRestart: Int
 | 
			
		||||
    waitForShutdown: Int
 | 
			
		||||
    cacheMaxMessages: Int
 | 
			
		||||
    featureFlags: [FeatureFlagInput]
 | 
			
		||||
    pingURLs: [String]
 | 
			
		||||
    technicianIds: [String]
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,8 @@ from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
from bot_api.logging.api_logger import ApiLogger
 | 
			
		||||
from bot_api.route.route import Route
 | 
			
		||||
from bot_core.service.config_service import ConfigService
 | 
			
		||||
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.model.server_afk_channel_ids_config import ServerAFKChannelIdsConfig
 | 
			
		||||
@@ -11,6 +13,7 @@ from bot_data.model.server_team_role_ids_config import ServerTeamRoleIdsConfig
 | 
			
		||||
from bot_data.model.team_member_type_enum import TeamMemberTypeEnum
 | 
			
		||||
from bot_data.model.user_role_enum import UserRoleEnum
 | 
			
		||||
from bot_graphql.abc.query_abc import QueryABC
 | 
			
		||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServerConfigMutation(QueryABC):
 | 
			
		||||
@@ -21,6 +24,8 @@ class ServerConfigMutation(QueryABC):
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
        server_configs: ServerConfigRepositoryABC,
 | 
			
		||||
        db: DatabaseContextABC,
 | 
			
		||||
        config_service: ConfigService,
 | 
			
		||||
        permissions: PermissionServiceABC,
 | 
			
		||||
    ):
 | 
			
		||||
        QueryABC.__init__(self, "ServerConfigMutation")
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +34,8 @@ class ServerConfigMutation(QueryABC):
 | 
			
		||||
        self._servers = servers
 | 
			
		||||
        self._server_configs = server_configs
 | 
			
		||||
        self._db = db
 | 
			
		||||
        self._config_service = config_service
 | 
			
		||||
        self._permissions = permissions
 | 
			
		||||
 | 
			
		||||
        self.set_field("updateServerConfig", self.resolve_update_server_config)
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +44,7 @@ class ServerConfigMutation(QueryABC):
 | 
			
		||||
            raise ValueError("Id not set")
 | 
			
		||||
 | 
			
		||||
        server_config = self._server_configs.get_server_config_by_server(input["id"])
 | 
			
		||||
        self._can_user_mutate_data(server_config, UserRoleEnum.admin)
 | 
			
		||||
        self._can_user_mutate_data(Route.get_user().users[0].server, UserRoleEnum.technician)
 | 
			
		||||
 | 
			
		||||
        server_config.message_delete_timer = (
 | 
			
		||||
            input["messageDeleteTimer"] if "messageDeleteTimer" in input else server_config.message_delete_timer
 | 
			
		||||
@@ -82,6 +89,11 @@ class ServerConfigMutation(QueryABC):
 | 
			
		||||
            if "loginMessageChannelId" in input
 | 
			
		||||
            else server_config.login_message_channel_id
 | 
			
		||||
        )
 | 
			
		||||
        server_config.feature_flags = (
 | 
			
		||||
            dict(zip([x["key"] for x in input["featureFlags"]], [x["value"] for x in input["featureFlags"]]))
 | 
			
		||||
            if "featureFlags" in input
 | 
			
		||||
            else server_config.feature_flags
 | 
			
		||||
        )
 | 
			
		||||
        server_config.afk_channel_ids = (
 | 
			
		||||
            List(int).extend([int(x) for x in input["afkChannelIds"]])
 | 
			
		||||
            if "afkChannelIds" in input
 | 
			
		||||
@@ -161,3 +173,6 @@ class ServerConfigMutation(QueryABC):
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            self._server_configs.add_server_team_role_id_config(role_id)
 | 
			
		||||
 | 
			
		||||
        self._config_service.reload_server_config(new_config.server)
 | 
			
		||||
        self._permissions.on_ready()
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@ from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
from bot_api.logging.api_logger import ApiLogger
 | 
			
		||||
from bot_api.route.route import Route
 | 
			
		||||
from bot_core.service.config_service import ConfigService
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
 | 
			
		||||
from bot_data.model.technician_config import TechnicianConfig
 | 
			
		||||
@@ -10,6 +12,7 @@ from bot_data.model.technician_id_config import TechnicianIdConfig
 | 
			
		||||
from bot_data.model.technician_ping_url_config import TechnicianPingUrlConfig
 | 
			
		||||
from bot_data.model.user_role_enum import UserRoleEnum
 | 
			
		||||
from bot_graphql.abc.query_abc import QueryABC
 | 
			
		||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TechnicianConfigMutation(QueryABC):
 | 
			
		||||
@@ -20,6 +23,8 @@ class TechnicianConfigMutation(QueryABC):
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
        technician_configs: TechnicianConfigRepositoryABC,
 | 
			
		||||
        db: DatabaseContextABC,
 | 
			
		||||
        permissions: PermissionServiceABC,
 | 
			
		||||
        config_service: ConfigService,
 | 
			
		||||
    ):
 | 
			
		||||
        QueryABC.__init__(self, "TechnicianConfigMutation")
 | 
			
		||||
 | 
			
		||||
@@ -28,12 +33,14 @@ class TechnicianConfigMutation(QueryABC):
 | 
			
		||||
        self._servers = servers
 | 
			
		||||
        self._technician_configs = technician_configs
 | 
			
		||||
        self._db = db
 | 
			
		||||
        self._permissions = permissions
 | 
			
		||||
        self._config_service = config_service
 | 
			
		||||
 | 
			
		||||
        self.set_field("updateTechnicianConfig", self.resolve_update_technician_config)
 | 
			
		||||
 | 
			
		||||
    def resolve_update_technician_config(self, *_, input: dict):
 | 
			
		||||
        technician_config = self._technician_configs.get_technician_config()
 | 
			
		||||
        self._can_user_mutate_data(technician_config, UserRoleEnum.admin)
 | 
			
		||||
        self._can_user_mutate_data(Route.get_user().users[0].server, UserRoleEnum.technician)
 | 
			
		||||
 | 
			
		||||
        technician_config.help_command_reference_url = (
 | 
			
		||||
            input["helpCommandReferenceUrl"]
 | 
			
		||||
@@ -49,6 +56,11 @@ class TechnicianConfigMutation(QueryABC):
 | 
			
		||||
        technician_config.cache_max_messages = (
 | 
			
		||||
            input["cacheMaxMessages"] if "cacheMaxMessages" in input else technician_config.cache_max_messages
 | 
			
		||||
        )
 | 
			
		||||
        technician_config.feature_flags = (
 | 
			
		||||
            dict(zip([x["key"] for x in input["featureFlags"]], [x["value"] for x in input["featureFlags"]]))
 | 
			
		||||
            if "featureFlags" in input
 | 
			
		||||
            else technician_config.feature_flags
 | 
			
		||||
        )
 | 
			
		||||
        technician_config.ping_urls = (
 | 
			
		||||
            List(str, input["pingURLs"]) if "pingURLs" in input else technician_config.ping_urls
 | 
			
		||||
        )
 | 
			
		||||
@@ -100,3 +112,6 @@ class TechnicianConfigMutation(QueryABC):
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            self._technician_configs.add_technician_id_config(TechnicianIdConfig(technician_id))
 | 
			
		||||
 | 
			
		||||
        self._config_service.reload_technician_config()
 | 
			
		||||
        self._permissions.on_ready()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
from bot_data.model.server_config_history import ServerConfigHistory
 | 
			
		||||
from bot_data.model.team_member_type_enum import TeamMemberTypeEnum
 | 
			
		||||
@@ -23,6 +24,10 @@ class ServerConfigQuery(DataQueryWithHistoryABC):
 | 
			
		||||
        self.set_field("helpVoiceChannelId", lambda config, *_: config.help_voice_channel_id)
 | 
			
		||||
        self.set_field("teamChannelId", lambda config, *_: config.team_channel_id)
 | 
			
		||||
        self.set_field("loginMessageChannelId", lambda config, *_: config.login_message_channel_id)
 | 
			
		||||
        self.add_collection(
 | 
			
		||||
            "featureFlag",
 | 
			
		||||
            lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
 | 
			
		||||
        )
 | 
			
		||||
        self.set_field("afkChannelIds", lambda config, *_: config.afk_channel_ids)
 | 
			
		||||
        self.set_field(
 | 
			
		||||
            "moderatorRoleIds",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
from cpl_query.extension import List
 | 
			
		||||
 | 
			
		||||
from bot_graphql.abc.history_query_abc import HistoryQueryABC
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -9,3 +11,7 @@ class TechnicianConfigHistoryQuery(HistoryQueryABC):
 | 
			
		||||
        self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
 | 
			
		||||
        self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
 | 
			
		||||
        self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
 | 
			
		||||
        self.add_collection(
 | 
			
		||||
            "featureFlag",
 | 
			
		||||
            lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
 | 
			
		||||
        )
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,10 @@ class TechnicianConfigQuery(DataQueryWithHistoryABC):
 | 
			
		||||
        self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
 | 
			
		||||
        self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
 | 
			
		||||
        self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
 | 
			
		||||
        self.add_collection(
 | 
			
		||||
            "featureFlag",
 | 
			
		||||
            lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
 | 
			
		||||
        )
 | 
			
		||||
        self.set_field("pingURLs", lambda config, *_: config.ping_urls)
 | 
			
		||||
        self.set_field("technicianIds", lambda config, *_: config.technician_ids)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
 | 
			
		||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
 | 
			
		||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
 | 
			
		||||
@@ -75,6 +76,7 @@ class Query(QueryABC):
 | 
			
		||||
        self.set_field("guilds", self._resolve_guilds)
 | 
			
		||||
        self.set_field("achievementAttributes", lambda x, *_: achievement_service.get_attributes())
 | 
			
		||||
        self.set_field("achievementOperators", lambda x, *_: achievement_service.get_operators())
 | 
			
		||||
        self.set_field("possibleFeatureFlags", lambda x, *_: [e.value for e in FeatureFlagsEnum])
 | 
			
		||||
 | 
			
		||||
    def _resolve_guilds(self, *_, filter=None):
 | 
			
		||||
        if filter is None or "id" not in filter:
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ from modules.achievements.events.achievement_on_message_event import Achievement
 | 
			
		||||
 | 
			
		||||
class AchievementsModule(ModuleABC):
 | 
			
		||||
    def __init__(self, dc: DiscordCollectionABC):
 | 
			
		||||
        ModuleABC.__init__(self, dc, FeatureFlagsEnum.auto_role_module)
 | 
			
		||||
        ModuleABC.__init__(self, dc, FeatureFlagsEnum.achievements_module)
 | 
			
		||||
 | 
			
		||||
    def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
 | 
			
		||||
        pass
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_discord.command import DiscordCommandABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from cpl_translation import TranslatePipe
 | 
			
		||||
@@ -6,16 +7,20 @@ from discord.ext import commands
 | 
			
		||||
from discord.ext.commands import Context
 | 
			
		||||
 | 
			
		||||
from bot_core.abc.message_service_abc import MessageServiceABC
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.command_checks import CommandChecks
 | 
			
		||||
from bot_core.logging.command_logger import CommandLogger
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.achievements.achievement_service import AchievementService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AchievementGroup(DiscordCommandABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: CommandLogger,
 | 
			
		||||
        message_service: MessageServiceABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
@@ -26,6 +31,7 @@ class AchievementGroup(DiscordCommandABC):
 | 
			
		||||
    ):
 | 
			
		||||
        DiscordCommandABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._message_service = message_service
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
@@ -45,6 +51,14 @@ class AchievementGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def check(self, ctx: Context, member: discord.Member):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command achievement check {ctx}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(
 | 
			
		||||
            server_config.feature_flags, FeatureFlagsEnum.achievements_module
 | 
			
		||||
        ):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server = self._servers.get_server_by_discord_id(member.guild.id)
 | 
			
		||||
        user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,23 @@
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.events import OnMessageABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.achievements.achievement_service import AchievementService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AchievementOnMessageEvent(OnMessageABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: LoggerABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        achievements: AchievementService,
 | 
			
		||||
@@ -22,6 +27,7 @@ class AchievementOnMessageEvent(OnMessageABC):
 | 
			
		||||
    ):
 | 
			
		||||
        OnMessageABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._achievements = achievements
 | 
			
		||||
@@ -31,9 +37,18 @@ class AchievementOnMessageEvent(OnMessageABC):
 | 
			
		||||
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_message(self, message: discord.Message):
 | 
			
		||||
        if message.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if message.author.bot:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{message.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(
 | 
			
		||||
            server_config.feature_flags, FeatureFlagsEnum.achievements_module
 | 
			
		||||
        ):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server = self._servers.get_server_by_discord_id(message.guild.id)
 | 
			
		||||
        user = self._users.get_user_by_discord_id_and_server_id(message.author.id, server.id)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from typing import List as TList
 | 
			
		||||
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_discord.command import DiscordCommandABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
@@ -12,18 +13,22 @@ from discord.ext.commands import Context
 | 
			
		||||
 | 
			
		||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
 | 
			
		||||
from bot_core.abc.message_service_abc import MessageServiceABC
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.command_checks import CommandChecks
 | 
			
		||||
from bot_core.logging.command_logger import CommandLogger
 | 
			
		||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.model.auto_role import AutoRole
 | 
			
		||||
from bot_data.model.auto_role_rule import AutoRoleRule
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: CommandLogger,
 | 
			
		||||
        message_service: MessageServiceABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
@@ -36,6 +41,7 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    ):
 | 
			
		||||
        DiscordCommandABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._message_service = message_service
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
@@ -69,10 +75,13 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def list(self, ctx: Context, wait: int = None):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command auto-role list {ctx}")
 | 
			
		||||
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        embed = discord.Embed(
 | 
			
		||||
            title=self._t.transform("modules.auto_role.list.title"),
 | 
			
		||||
            description=self._t.transform("modules.auto_role.list.description"),
 | 
			
		||||
@@ -110,6 +119,12 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def add(self, ctx: Context, channel: discord.TextChannel, message_id: str):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command auto-role add {ctx} {message_id}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        message = (
 | 
			
		||||
            List(
 | 
			
		||||
@@ -170,6 +185,12 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def remove(self, ctx: Context, auto_role: int):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command auto-role remove {ctx} {auto_role}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        auto_role_from_db = self._auto_roles.find_auto_role_by_id(auto_role)
 | 
			
		||||
        if auto_role_from_db is None:
 | 
			
		||||
@@ -210,6 +231,12 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def list(self, ctx: Context, auto_role: int, wait: int = None):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command auto-role rule list {ctx}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        embed = discord.Embed(
 | 
			
		||||
            title=self._t.transform("modules.auto_role.list.title"),
 | 
			
		||||
@@ -262,6 +289,12 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def add(self, ctx: Context, auto_role: int, emoji_name: str, role_id: str):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command auto-role add {ctx} {auto_role}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        emoji = discord.utils.get(self._bot.emojis, name=emoji_name)
 | 
			
		||||
        if emoji is None:
 | 
			
		||||
@@ -354,6 +387,12 @@ class AutoRoleGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def remove(self, ctx: Context, auto_role_rule: int):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command auto-role remove {ctx} {auto_role_rule}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        auto_role_from_db = self._auto_roles.get_auto_role_rule_by_id(auto_role_rule)
 | 
			
		||||
        if auto_role_from_db is None:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,22 @@
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.events.on_raw_reaction_add_abc import OnRawReactionAddABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from discord import RawReactionActionEvent
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.auto_role.helper.auto_role_reaction_handler import AutoRoleReactionHandler
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AutoRoleOnRawReactionAddEvent(OnRawReactionAddABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: LoggerABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
@@ -20,6 +25,7 @@ class AutoRoleOnRawReactionAddEvent(OnRawReactionAddABC):
 | 
			
		||||
    ):
 | 
			
		||||
        OnRawReactionAddABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._servers = servers
 | 
			
		||||
@@ -29,6 +35,9 @@ class AutoRoleOnRawReactionAddEvent(OnRawReactionAddABC):
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        await self._reaction_handler.handle(payload, "add")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,22 @@
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.events.on_raw_reaction_remove_abc import OnRawReactionRemoveABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from discord import RawReactionActionEvent
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.auto_role.helper.auto_role_reaction_handler import AutoRoleReactionHandler
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AutoRoleOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: LoggerABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
@@ -20,6 +25,7 @@ class AutoRoleOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
 | 
			
		||||
    ):
 | 
			
		||||
        OnRawReactionRemoveABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._servers = servers
 | 
			
		||||
@@ -29,6 +35,9 @@ class AutoRoleOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.auto_role_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        await self._reaction_handler.handle(payload, "remove")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from typing import Optional
 | 
			
		||||
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_core.time import TimeFormatSettings
 | 
			
		||||
from cpl_discord.events import OnCommandABC
 | 
			
		||||
@@ -13,12 +14,14 @@ from bot_core.logging.command_logger import CommandLogger
 | 
			
		||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from bot_data.model.user import User
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BaseOnCommandEvent(OnCommandABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: CommandLogger,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        messenger: MessageServiceABC,
 | 
			
		||||
@@ -30,6 +33,7 @@ class BaseOnCommandEvent(OnCommandABC):
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
    ):
 | 
			
		||||
        OnCommandABC.__init__(self)
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._messenger = messenger
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from typing import Optional
 | 
			
		||||
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_discord.events import OnMessageDeleteABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
@@ -10,12 +11,14 @@ from bot_core.logging.message_logger import MessageLogger
 | 
			
		||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from bot_data.model.user import User
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BaseOnMessageDeleteEvent(OnMessageDeleteABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: MessageLogger,
 | 
			
		||||
        db: DatabaseContextABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
@@ -24,6 +27,7 @@ class BaseOnMessageDeleteEvent(OnMessageDeleteABC):
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
    ):
 | 
			
		||||
        OnMessageDeleteABC.__init__(self)
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._db = db
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@ from cpl_translation import TranslatePipe
 | 
			
		||||
from discord import guild
 | 
			
		||||
 | 
			
		||||
from bot_core.abc.message_service_abc import MessageServiceABC
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -60,6 +62,11 @@ class BootLogOnReadyEvent(OnReadyABC):
 | 
			
		||||
                self._logger.error(__name__, f"Config {type(self).__name__}_{g.id} not found!")
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            if not FeatureFlagsSettings.get_flag_from_dict(
 | 
			
		||||
                server_config.feature_flags, FeatureFlagsEnum.boot_log_module
 | 
			
		||||
            ):
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            self._bot.loop.create_task(
 | 
			
		||||
                self._message_service.send_channel_message(
 | 
			
		||||
                    self._bot.get_channel(server_config.login_message_channel_id),
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,7 @@ from cpl_core.logging import LoggerABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
 | 
			
		||||
from bot_data.model.technician_config import TechnicianConfig
 | 
			
		||||
from bot_core.service.config_service import ConfigService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConfigExtension(ApplicationExtensionABC):
 | 
			
		||||
@@ -19,6 +18,5 @@ class ConfigExtension(ApplicationExtensionABC):
 | 
			
		||||
            return
 | 
			
		||||
        logger: LoggerABC = services.get_service(LoggerABC)
 | 
			
		||||
        logger.debug(__name__, "Config extension started")
 | 
			
		||||
        technician_config_repo: TechnicianConfigRepositoryABC = services.get_service(TechnicianConfigRepositoryABC)
 | 
			
		||||
        technician_config = technician_config_repo.get_technician_config()
 | 
			
		||||
        config.add_configuration(TechnicianConfig, technician_config)
 | 
			
		||||
        config: ConfigService = services.get_service(ConfigService)
 | 
			
		||||
        config.reload_technician_config()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,9 @@
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.container import Guild
 | 
			
		||||
from cpl_discord.events import OnReadyABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
 | 
			
		||||
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
 | 
			
		||||
from bot_core.service.config_service import ConfigService
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -15,7 +14,7 @@ class ConfigOnReadyEvent(OnReadyABC):
 | 
			
		||||
        logger: LoggerABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        servers: ServerRepositoryABC,
 | 
			
		||||
        server_config_repo: ServerConfigRepositoryABC,
 | 
			
		||||
        config_service: ConfigService,
 | 
			
		||||
    ):
 | 
			
		||||
        OnReadyABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
@@ -23,13 +22,8 @@ class ConfigOnReadyEvent(OnReadyABC):
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._servers = servers
 | 
			
		||||
        self._server_config_repo = server_config_repo
 | 
			
		||||
        self._config_service = config_service
 | 
			
		||||
 | 
			
		||||
    async def on_ready(self):
 | 
			
		||||
        for guild in self._bot.guilds:
 | 
			
		||||
            guild: Guild = guild
 | 
			
		||||
            server = self._servers.get_server_by_discord_id(guild.id)
 | 
			
		||||
            server_config = self._server_config_repo.get_server_config_by_server(server.id)
 | 
			
		||||
            self._config.add_configuration(
 | 
			
		||||
                f"{type(server_config).__name__}_{server_config.server.discord_id}", server_config
 | 
			
		||||
            )
 | 
			
		||||
            self._config_service.reload_server_config(self._servers.get_server_by_discord_id(guild.id))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from typing import List as TList
 | 
			
		||||
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.database.context import DatabaseContextABC
 | 
			
		||||
from cpl_discord.command import DiscordCommandABC
 | 
			
		||||
from cpl_discord.container import Guild, Role
 | 
			
		||||
@@ -12,12 +13,15 @@ from discord.ext.commands import Context
 | 
			
		||||
 | 
			
		||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
 | 
			
		||||
from bot_core.abc.message_service_abc import MessageServiceABC
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.command_checks import CommandChecks
 | 
			
		||||
from bot_core.logging.command_logger import CommandLogger
 | 
			
		||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
 | 
			
		||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
			
		||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
			
		||||
from bot_data.model.level import Level
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.level.level_seeder import LevelSeeder
 | 
			
		||||
from modules.level.service.level_service import LevelService
 | 
			
		||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
 | 
			
		||||
@@ -26,6 +30,7 @@ from modules.permission.abc.permission_service_abc import PermissionServiceABC
 | 
			
		||||
class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: CommandLogger,
 | 
			
		||||
        message_service: MessageServiceABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
@@ -41,6 +46,7 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    ):
 | 
			
		||||
        DiscordCommandABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._message_service = message_service
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
@@ -125,10 +131,13 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def list(self, ctx: Context, wait: int = None):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level list {ctx}")
 | 
			
		||||
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server = self._servers.get_server_by_discord_id(ctx.guild.id)
 | 
			
		||||
        levels = self._levels.get_levels_by_server_id(server.id)
 | 
			
		||||
        if levels.count() < 1:
 | 
			
		||||
@@ -169,6 +178,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_admin()
 | 
			
		||||
    async def create(self, ctx: Context, name: str, color: str, min_xp: int, permissions: int):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level create {ctx}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            color = hex(discord.Colour.from_str(color).value)
 | 
			
		||||
@@ -258,6 +273,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
        permissions: int = None,
 | 
			
		||||
    ):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level edit {ctx}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server = self._servers.get_server_by_discord_id(ctx.guild.id)
 | 
			
		||||
        level_from_db = (
 | 
			
		||||
@@ -350,6 +371,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_admin()
 | 
			
		||||
    async def remove(self, ctx: Context, level: str):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level remove {ctx}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server = self._servers.get_server_by_discord_id(ctx.guild.id)
 | 
			
		||||
        level_from_db = (
 | 
			
		||||
@@ -394,6 +421,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def down(self, ctx: Context, member: discord.Member):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level down {ctx} {member}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if member.bot:
 | 
			
		||||
            return
 | 
			
		||||
@@ -436,6 +469,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def up(self, ctx: Context, member: discord.Member):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level up {ctx} {member}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if member.bot:
 | 
			
		||||
            return
 | 
			
		||||
@@ -477,6 +516,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def set(self, ctx: Context, member: discord.Member, level: str):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level up {ctx} {member}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if member.bot:
 | 
			
		||||
            return
 | 
			
		||||
@@ -529,5 +574,12 @@ class LevelGroup(DiscordCommandABC):
 | 
			
		||||
    @CommandChecks.check_is_member_moderator()
 | 
			
		||||
    async def reload(self, ctx: Context):
 | 
			
		||||
        self._logger.debug(__name__, f"Received command level reload {ctx}")
 | 
			
		||||
        if ctx.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        await self._seed_levels(ctx)
 | 
			
		||||
        self._logger.trace(__name__, f"Finished command level reload")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,27 @@
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_discord.events import OnMemberJoinABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_core.logging.message_logger import MessageLogger
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.level.service.level_service import LevelService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LevelOnMemberJoinEvent(OnMemberJoinABC):
 | 
			
		||||
    def __init__(self, logger: MessageLogger, level: LevelService):
 | 
			
		||||
    def __init__(self, config: ConfigurationABC, logger: MessageLogger, level: LevelService):
 | 
			
		||||
        OnMemberJoinABC.__init__(self)
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._level = level
 | 
			
		||||
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_member_join(self, member: discord.Member):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        await self._level.check_level(member)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,35 @@
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_discord.events import OnMessageABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_core.logging.message_logger import MessageLogger
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.level.service.level_service import LevelService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LevelOnMessageEvent(OnMessageABC):
 | 
			
		||||
    def __init__(self, logger: MessageLogger, level: LevelService):
 | 
			
		||||
    def __init__(self, config: ConfigurationABC, logger: MessageLogger, level: LevelService):
 | 
			
		||||
        OnMessageABC.__init__(self)
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._level = level
 | 
			
		||||
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_message(self, message: discord.Message):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        if message.guild is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if message.author.bot:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{message.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            await self._level.check_level(message.author)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,27 @@
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.events.on_raw_reaction_add_abc import OnRawReactionAddABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from discord import RawReactionActionEvent
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.level.service.level_service import LevelService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LevelOnRawReactionAddEvent(OnRawReactionAddABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: LoggerABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        level: LevelService,
 | 
			
		||||
    ):
 | 
			
		||||
        OnRawReactionAddABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._level = level
 | 
			
		||||
@@ -23,6 +29,10 @@ class LevelOnRawReactionAddEvent(OnRawReactionAddABC):
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            self._logger.trace(__name__, f"Handle reaction {payload} for level")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,27 @@
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.events.on_raw_reaction_remove_abc import OnRawReactionRemoveABC
 | 
			
		||||
from cpl_discord.service import DiscordBotServiceABC
 | 
			
		||||
from discord import RawReactionActionEvent
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.level.service.level_service import LevelService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LevelOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        config: ConfigurationABC,
 | 
			
		||||
        logger: LoggerABC,
 | 
			
		||||
        bot: DiscordBotServiceABC,
 | 
			
		||||
        level: LevelService,
 | 
			
		||||
    ):
 | 
			
		||||
        OnRawReactionRemoveABC.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._bot = bot
 | 
			
		||||
        self._level = level
 | 
			
		||||
@@ -23,6 +29,10 @@ class LevelOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
 | 
			
		||||
    @EventChecks.check_is_ready()
 | 
			
		||||
    async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            self._logger.trace(__name__, f"Handle reaction {payload} for level")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,19 @@
 | 
			
		||||
import discord
 | 
			
		||||
from cpl_core.configuration import ConfigurationABC
 | 
			
		||||
from cpl_core.logging import LoggerABC
 | 
			
		||||
from cpl_discord.events import OnVoiceStateUpdateABC
 | 
			
		||||
 | 
			
		||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
			
		||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
			
		||||
from bot_core.helper.event_checks import EventChecks
 | 
			
		||||
from bot_data.model.server_config import ServerConfig
 | 
			
		||||
from modules.level.service.level_service import LevelService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LevelOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
 | 
			
		||||
    def __init__(self, logger: LoggerABC, level: LevelService):
 | 
			
		||||
    def __init__(self, config: ConfigurationABC, logger: LoggerABC, level: LevelService):
 | 
			
		||||
        OnVoiceStateUpdateABC.__init__(self)
 | 
			
		||||
        self._config = config
 | 
			
		||||
        self._logger = logger
 | 
			
		||||
        self._level = level
 | 
			
		||||
 | 
			
		||||
@@ -22,4 +27,8 @@ class LevelOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
 | 
			
		||||
        after: discord.VoiceState,
 | 
			
		||||
    ):
 | 
			
		||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
			
		||||
        server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
 | 
			
		||||
        if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        await self._level.check_level(member)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "kdb-web",
 | 
			
		||||
    "version": "1.1.dev79_hide_table_columns",
 | 
			
		||||
    "version": "1.1.dev334_feature_flags_in_wi",
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "ng": "ng",
 | 
			
		||||
        "update-version": "ts-node-esm update-version.ts",
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,12 @@ export class ComponentWithTable {
 | 
			
		||||
    this.columns = columns.map(column => {
 | 
			
		||||
      return { key: this.getKey(column), name: column };
 | 
			
		||||
    });
 | 
			
		||||
    this._hiddenColumns = JSON.parse(localStorage.getItem("hiddenColumns") ?? "");
 | 
			
		||||
    let hiddenColumns = localStorage.getItem("hiddenColumns");
 | 
			
		||||
    if (!hiddenColumns) {
 | 
			
		||||
      localStorage.setItem("hiddenColumns", JSON.stringify([{}]));
 | 
			
		||||
      hiddenColumns = localStorage.getItem("hiddenColumns") ?? JSON.stringify([{}]);
 | 
			
		||||
    }
 | 
			
		||||
    this._hiddenColumns = JSON.parse(hiddenColumns);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getKey(column: string): string {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								kdb-web/src/app/models/config/feature-flags.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								kdb-web/src/app/models/config/feature-flags.model.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
export interface FeatureFlag {
 | 
			
		||||
  key: string;
 | 
			
		||||
  value: boolean;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import { DataWithHistory } from "../data/data.model";
 | 
			
		||||
import { FeatureFlag } from "./feature-flags.model";
 | 
			
		||||
 | 
			
		||||
export interface ServerConfig extends DataWithHistory {
 | 
			
		||||
  id?: number;
 | 
			
		||||
@@ -15,6 +16,7 @@ export interface ServerConfig extends DataWithHistory {
 | 
			
		||||
  helpVoiceChannelId?: string;
 | 
			
		||||
  teamChannelId?: string;
 | 
			
		||||
  loginMessageChannelId?: string;
 | 
			
		||||
  featureFlags: FeatureFlag[];
 | 
			
		||||
  afkChannelIds: string[];
 | 
			
		||||
  moderatorRoleIds: string[];
 | 
			
		||||
  adminRoleIds: string[];
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import { DataWithHistory } from "../data/data.model";
 | 
			
		||||
import { FeatureFlag } from "./feature-flags.model";
 | 
			
		||||
 | 
			
		||||
export interface TechnicianConfig extends DataWithHistory {
 | 
			
		||||
  id?: number;
 | 
			
		||||
@@ -6,6 +7,7 @@ export interface TechnicianConfig extends DataWithHistory {
 | 
			
		||||
  waitForRestart?: number;
 | 
			
		||||
  waitForShutdown?: number;
 | 
			
		||||
  cacheMaxMessages?: number;
 | 
			
		||||
  featureFlags: FeatureFlag[];
 | 
			
		||||
  pingURLs: string[];
 | 
			
		||||
  technicianIds: string[];
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -167,7 +167,7 @@ export class Mutations {
 | 
			
		||||
  `;
 | 
			
		||||
 | 
			
		||||
  static updateTechnicianConfig = `
 | 
			
		||||
    mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $pingURLs: [String], $technicianIds: [String]) {
 | 
			
		||||
    mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $featureFlags: [FeatureFlagInput], $pingURLs: [String], $technicianIds: [String]) {
 | 
			
		||||
      technicianConfig {
 | 
			
		||||
        updateTechnicianConfig(input: {
 | 
			
		||||
            id: $id,
 | 
			
		||||
@@ -175,6 +175,7 @@ export class Mutations {
 | 
			
		||||
            waitForRestart: $waitForRestart,
 | 
			
		||||
            waitForShutdown: $waitForShutdown,
 | 
			
		||||
            cacheMaxMessages: $cacheMaxMessages,
 | 
			
		||||
            featureFlags: $featureFlags,
 | 
			
		||||
            pingURLs: $pingURLs,
 | 
			
		||||
            technicianIds: $technicianIds
 | 
			
		||||
          }) {
 | 
			
		||||
@@ -183,6 +184,10 @@ export class Mutations {
 | 
			
		||||
          waitForRestart
 | 
			
		||||
          waitForShutdown
 | 
			
		||||
          cacheMaxMessages
 | 
			
		||||
          featureFlags {
 | 
			
		||||
            key
 | 
			
		||||
            value
 | 
			
		||||
          }
 | 
			
		||||
          pingURLs
 | 
			
		||||
          technicianIds
 | 
			
		||||
        }
 | 
			
		||||
@@ -206,6 +211,7 @@ export class Mutations {
 | 
			
		||||
      $helpVoiceChannelId: String,
 | 
			
		||||
      $teamChannelId: String,
 | 
			
		||||
      $loginMessageChannelId: String,
 | 
			
		||||
      $featureFlags: [FeatureFlagInput],
 | 
			
		||||
      $afkChannelIds: [String],
 | 
			
		||||
      $moderatorRoleIds: [String],
 | 
			
		||||
      $adminRoleIds: [String]
 | 
			
		||||
@@ -213,21 +219,22 @@ export class Mutations {
 | 
			
		||||
      serverConfig {
 | 
			
		||||
        updateServerConfig(input: {
 | 
			
		||||
            id: $id,
 | 
			
		||||
            messageDeleteTimer: $messageDeleteTimer
 | 
			
		||||
            notificationChatId: $notificationChatId
 | 
			
		||||
            maxVoiceStateHours: $maxVoiceStateHours
 | 
			
		||||
            xpPerMessage: $xpPerMessage
 | 
			
		||||
            xpPerReaction: $xpPerReaction
 | 
			
		||||
            maxMessageXpPerHour: $maxMessageXpPerHour
 | 
			
		||||
            xpPerOntimeHour: $xpPerOntimeHour
 | 
			
		||||
            xpPerEventParticipation: $xpPerEventParticipation
 | 
			
		||||
            xpPerAchievement: $xpPerAchievement
 | 
			
		||||
            afkCommandChannelId: $afkCommandChannelId
 | 
			
		||||
            helpVoiceChannelId: $helpVoiceChannelId
 | 
			
		||||
            teamChannelId: $teamChannelId
 | 
			
		||||
            loginMessageChannelId: $loginMessageChannelId
 | 
			
		||||
            afkChannelIds: $afkChannelIds
 | 
			
		||||
            moderatorRoleIds: $moderatorRoleIds
 | 
			
		||||
            messageDeleteTimer: $messageDeleteTimer,
 | 
			
		||||
            notificationChatId: $notificationChatId,
 | 
			
		||||
            maxVoiceStateHours: $maxVoiceStateHours,
 | 
			
		||||
            xpPerMessage: $xpPerMessage,
 | 
			
		||||
            xpPerReaction: $xpPerReaction,
 | 
			
		||||
            maxMessageXpPerHour: $maxMessageXpPerHour,
 | 
			
		||||
            xpPerOntimeHour: $xpPerOntimeHour,
 | 
			
		||||
            xpPerEventParticipation: $xpPerEventParticipation,
 | 
			
		||||
            xpPerAchievement: $xpPerAchievement,
 | 
			
		||||
            afkCommandChannelId: $afkCommandChannelId,
 | 
			
		||||
            helpVoiceChannelId: $helpVoiceChannelId,
 | 
			
		||||
            teamChannelId: $teamChannelId,
 | 
			
		||||
            loginMessageChannelId: $loginMessageChannelId,
 | 
			
		||||
            featureFlags: $featureFlags,
 | 
			
		||||
            afkChannelIds: $afkChannelIds,
 | 
			
		||||
            moderatorRoleIds: $moderatorRoleIds,
 | 
			
		||||
            adminRoleIds: $adminRoleIds
 | 
			
		||||
          }) {
 | 
			
		||||
          id
 | 
			
		||||
@@ -244,6 +251,10 @@ export class Mutations {
 | 
			
		||||
          helpVoiceChannelId
 | 
			
		||||
          teamChannelId
 | 
			
		||||
          loginMessageChannelId
 | 
			
		||||
          featureFlags {
 | 
			
		||||
            key
 | 
			
		||||
            value
 | 
			
		||||
          }
 | 
			
		||||
          afkChannelIds
 | 
			
		||||
          moderatorRoleIds
 | 
			
		||||
          adminRoleIds
 | 
			
		||||
 
 | 
			
		||||
@@ -353,6 +353,10 @@ export class Queries {
 | 
			
		||||
        waitForRestart
 | 
			
		||||
        waitForShutdown
 | 
			
		||||
        cacheMaxMessages
 | 
			
		||||
        featureFlags {
 | 
			
		||||
          key
 | 
			
		||||
          value
 | 
			
		||||
        }
 | 
			
		||||
        pingURLs
 | 
			
		||||
        technicianIds
 | 
			
		||||
 | 
			
		||||
@@ -381,6 +385,10 @@ export class Queries {
 | 
			
		||||
          helpVoiceChannelId
 | 
			
		||||
          teamChannelId
 | 
			
		||||
          loginMessageChannelId
 | 
			
		||||
          featureFlags {
 | 
			
		||||
            key
 | 
			
		||||
            value
 | 
			
		||||
          }
 | 
			
		||||
          afkChannelIds
 | 
			
		||||
          moderatorRoleIds
 | 
			
		||||
          adminRoleIds
 | 
			
		||||
 
 | 
			
		||||
@@ -59,3 +59,8 @@ export interface AutoRoleRuleQuery {
 | 
			
		||||
  autoRoleRules: AutoRoleRule[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface PossibleFeatureFlagsQuery {
 | 
			
		||||
  possibleFeatureFlags: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -163,6 +163,7 @@
 | 
			
		||||
    <div class="content-divider"></div>
 | 
			
		||||
    <app-config-list translationKey="admin.settings.bot.ping_urls" [(data)]="config.pingURLs"></app-config-list>
 | 
			
		||||
    <app-config-list translationKey="admin.settings.bot.technician_ids" [(data)]="config.technicianIds"></app-config-list>
 | 
			
		||||
    <app-feature-flag-list [(data)]="config.featureFlags"></app-feature-flag-list>
 | 
			
		||||
 | 
			
		||||
    <div class="content-row">
 | 
			
		||||
      <button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ export class SettingsComponent implements OnInit {
 | 
			
		||||
    waitForRestart: 0,
 | 
			
		||||
    waitForShutdown: 0,
 | 
			
		||||
    cacheMaxMessages: 0,
 | 
			
		||||
    featureFlags: [],
 | 
			
		||||
    pingURLs: [],
 | 
			
		||||
    technicianIds: []
 | 
			
		||||
  };
 | 
			
		||||
@@ -150,6 +151,7 @@ export class SettingsComponent implements OnInit {
 | 
			
		||||
        waitForRestart: this.config.waitForRestart,
 | 
			
		||||
        waitForShutdown: this.config.waitForShutdown,
 | 
			
		||||
        cacheMaxMessages: this.config.cacheMaxMessages,
 | 
			
		||||
        featureFlags: this.config.featureFlags,
 | 
			
		||||
        pingURLs: this.config.pingURLs,
 | 
			
		||||
        technicianIds: this.config.technicianIds
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,10 @@
 | 
			
		||||
  <p-multiSelect display="chip" [options]="columns" [(ngModel)]="hiddenColumns" optionLabel="name" placeholder="{{'common.hidden_columns' | translate}}" [filter]=false>
 | 
			
		||||
    <ng-template let-value pTemplate="selectedItems">
 | 
			
		||||
      <div *ngFor="let item of hiddenColumns; let i = index;">
 | 
			
		||||
        <div>
 | 
			
		||||
        <div *ngIf="item.name">
 | 
			
		||||
          {{'common.' + item.name | translate}}<span *ngIf="i < columns.length-1">,</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div *ngIf="!item.name">{{'common.hidden_columns' | translate}}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div *ngIf="!hiddenColumns || hiddenColumns.length === 0">{{'common.hidden_columns' | translate}}</div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@
 | 
			
		||||
          </div>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
        <ng-template pTemplate="body" let-value let-editing="editing" let-ri="rowIndex">
 | 
			
		||||
          <tr [pEditableRow]="value">
 | 
			
		||||
            <td>
 | 
			
		||||
          <tr [pEditableRow]="value" style="display: flex;">
 | 
			
		||||
            <td style="flex: 1;">
 | 
			
		||||
              <p-cellEditor>
 | 
			
		||||
                <ng-template pTemplate="input">
 | 
			
		||||
                  <input class="table-edit-input" pInputText type="text" [(ngModel)]="value.value">
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
<div class="content-row">
 | 
			
		||||
  <div class="content-column">
 | 
			
		||||
    <div class="content-data-name">
 | 
			
		||||
      {{'common.feature_flags' | translate}}:
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="content-data-value-row">
 | 
			
		||||
      <p-table #dt [value]="internal_data" dataKey="id" editMode="row">
 | 
			
		||||
        <ng-template pTemplate="caption">
 | 
			
		||||
          <div class="table-caption">
 | 
			
		||||
            <div class="table-caption-btn-wrapper btn-wrapper">
 | 
			
		||||
              <button pButton class="icon-btn btn"
 | 
			
		||||
                      icon="pi pi-plus" (click)="addNew(dt)">
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
        <ng-template pTemplate="body" let-value let-editing="editing" let-ri="rowIndex">
 | 
			
		||||
          <tr [pEditableRow]="value" style="display: flex;">
 | 
			
		||||
            <td style="flex: 3;">
 | 
			
		||||
              <p-cellEditor>
 | 
			
		||||
                <ng-template pTemplate="input">
 | 
			
		||||
                  <p-dropdown class="table-edit-input" [options]="featureFlags" [(ngModel)]="value.value.key"></p-dropdown>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <ng-template pTemplate="output">
 | 
			
		||||
                  {{value.value.key}}
 | 
			
		||||
                </ng-template>
 | 
			
		||||
              </p-cellEditor>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td style="flex: 1;">
 | 
			
		||||
              <p-cellEditor>
 | 
			
		||||
                <ng-template pTemplate="input">
 | 
			
		||||
                  <p-inputSwitch class="table-edit-input" [(ngModel)]="value.value.value"></p-inputSwitch>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <ng-template pTemplate="output">
 | 
			
		||||
                  <p-inputSwitch class="table-edit-input" [(ngModel)]="value.value.value" [disabled]="true"></p-inputSwitch>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
              </p-cellEditor>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
              <div class="btn-wrapper">
 | 
			
		||||
                <button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="editInit(value, ri)"></button>
 | 
			
		||||
                <button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="delete(ri)"></button>
 | 
			
		||||
 | 
			
		||||
                <button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="editSave(value, ri)"></button>
 | 
			
		||||
                <button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
 | 
			
		||||
                        (click)="editCancel(ri)"></button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
      </p-table>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="content-divider"></div>
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
			
		||||
 | 
			
		||||
import { FeatureFlagListComponent } from './feature-flag-list.component';
 | 
			
		||||
 | 
			
		||||
describe('FeatureFlagListComponent', () => {
 | 
			
		||||
  let component: FeatureFlagListComponent;
 | 
			
		||||
  let fixture: ComponentFixture<FeatureFlagListComponent>;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    await TestBed.configureTestingModule({
 | 
			
		||||
      declarations: [ FeatureFlagListComponent ]
 | 
			
		||||
    })
 | 
			
		||||
    .compileComponents();
 | 
			
		||||
 | 
			
		||||
    fixture = TestBed.createComponent(FeatureFlagListComponent);
 | 
			
		||||
    component = fixture.componentInstance;
 | 
			
		||||
    fixture.detectChanges();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create', () => {
 | 
			
		||||
    expect(component).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
import { Component, OnInit } from "@angular/core";
 | 
			
		||||
import { ConfigListComponent } from "../config-list/config-list.component";
 | 
			
		||||
import { Table } from "primeng/table";
 | 
			
		||||
import { PossibleFeatureFlagsQuery } from "../../../../models/graphql/query.model";
 | 
			
		||||
import { DataService } from "../../../../services/data/data.service";
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: "app-feature-flag-list",
 | 
			
		||||
  templateUrl: "./feature-flag-list.component.html",
 | 
			
		||||
  styleUrls: ["./feature-flag-list.component.scss"]
 | 
			
		||||
})
 | 
			
		||||
export class FeatureFlagListComponent extends ConfigListComponent implements OnInit {
 | 
			
		||||
  featureFlags: string[] = [];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private dataService: DataService
 | 
			
		||||
  ) {
 | 
			
		||||
    super();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.dataService.query<PossibleFeatureFlagsQuery>("{possibleFeatureFlags}"
 | 
			
		||||
    ).subscribe(data => {
 | 
			
		||||
      this.featureFlags = data.possibleFeatureFlags;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override addNew(table: Table) {
 | 
			
		||||
    const id = Math.max.apply(Math, this.internal_data.map(value => {
 | 
			
		||||
      return value.id ?? 0;
 | 
			
		||||
    })) + 1;
 | 
			
		||||
    const newItem = { id: id, value: { key: "", value: false } };
 | 
			
		||||
    this.internal_data.push(newItem);
 | 
			
		||||
 | 
			
		||||
    table.initRowEdit(newItem);
 | 
			
		||||
    const index = this.internal_data.findIndex(l => l.id == newItem.id);
 | 
			
		||||
    this.editInit(newItem, index);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -28,8 +28,11 @@ export class AuthGuard implements CanActivate {
 | 
			
		||||
 | 
			
		||||
    const role = route.data['role'];
 | 
			
		||||
    if (role) {
 | 
			
		||||
      this.authService.hasUserPermission(role).then(hasPermission => {
 | 
			
		||||
        if (!hasPermission) {
 | 
			
		||||
      this.authService.hasUserPermission(role).then(async hasPermission => {
 | 
			
		||||
        let authUser = await this.authService.getLoggedInUser();
 | 
			
		||||
        let isTechnician = authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? [];
 | 
			
		||||
 | 
			
		||||
        if (!hasPermission && !isTechnician) {
 | 
			
		||||
          this.router.navigate(['/dashboard']);
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,8 @@ import { MultiSelectModule } from "primeng/multiselect";
 | 
			
		||||
import { HideableColumnComponent } from './components/hideable-column/hideable-column.component';
 | 
			
		||||
import { HideableHeaderComponent } from './components/hideable-header/hideable-header.component';
 | 
			
		||||
import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-select-columns.component';
 | 
			
		||||
import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component';
 | 
			
		||||
import { InputSwitchModule } from "primeng/inputswitch";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
@@ -42,6 +44,7 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s
 | 
			
		||||
    HideableColumnComponent,
 | 
			
		||||
    HideableHeaderComponent,
 | 
			
		||||
    MultiSelectColumnsComponent,
 | 
			
		||||
    FeatureFlagListComponent,
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
@@ -68,6 +71,7 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s
 | 
			
		||||
    SidebarModule,
 | 
			
		||||
    DataViewModule,
 | 
			
		||||
    MultiSelectModule,
 | 
			
		||||
    InputSwitchModule,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    ButtonModule,
 | 
			
		||||
@@ -102,6 +106,8 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s
 | 
			
		||||
    HideableColumnComponent,
 | 
			
		||||
    HideableHeaderComponent,
 | 
			
		||||
    MultiSelectColumnsComponent,
 | 
			
		||||
    FeatureFlagListComponent,
 | 
			
		||||
    InputSwitchModule,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class SharedModule {
 | 
			
		||||
 
 | 
			
		||||
@@ -113,6 +113,7 @@
 | 
			
		||||
    <app-config-list translationKey="view.server.config.bot.afk_channels" [(data)]="config.afkChannelIds"></app-config-list>
 | 
			
		||||
    <app-config-list translationKey="view.server.config.bot.moderator_roles" [(data)]="config.moderatorRoleIds"></app-config-list>
 | 
			
		||||
    <app-config-list translationKey="view.server.config.bot.admin_roles" [(data)]="config.adminRoleIds"></app-config-list>
 | 
			
		||||
    <app-feature-flag-list *ngIf="isTechnician" [(data)]="config.featureFlags"></app-feature-flag-list>
 | 
			
		||||
 | 
			
		||||
    <div class="content-row">
 | 
			
		||||
      <button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ import { AuthService } from "../../../../../../services/auth/auth.service";
 | 
			
		||||
import { ServerConfig } from "../../../../../../models/config/server-config.model";
 | 
			
		||||
import { Server } from "../../../../../../models/data/server.model";
 | 
			
		||||
import { ActivatedRoute } from "@angular/router";
 | 
			
		||||
import { Table } from "primeng/table";
 | 
			
		||||
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
 | 
			
		||||
 | 
			
		||||
type AFKChannelId = {
 | 
			
		||||
  id: number;
 | 
			
		||||
@@ -31,6 +31,7 @@ type AFKChannelId = {
 | 
			
		||||
export class ConfigComponent implements OnInit {
 | 
			
		||||
  config: ServerConfig = {
 | 
			
		||||
    messageDeleteTimer: 0,
 | 
			
		||||
    featureFlags: [],
 | 
			
		||||
    afkChannelIds: [],
 | 
			
		||||
    moderatorRoleIds: [],
 | 
			
		||||
    adminRoleIds: []
 | 
			
		||||
@@ -41,6 +42,7 @@ export class ConfigComponent implements OnInit {
 | 
			
		||||
  clonedAfkChannelIds: { [s: number]: AFKChannelId } = {};
 | 
			
		||||
 | 
			
		||||
  private server: Server = {};
 | 
			
		||||
  isTechnician: boolean = false;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private data: DataService,
 | 
			
		||||
@@ -62,6 +64,9 @@ export class ConfigComponent implements OnInit {
 | 
			
		||||
    this.data.getServerFromRoute(this.route).then(async server => {
 | 
			
		||||
      this.server = server;
 | 
			
		||||
      this.loadConfig();
 | 
			
		||||
      let authUser = await this.authService.getLoggedInUser();
 | 
			
		||||
      let isUserTechnicianList = authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? [];
 | 
			
		||||
      this.isTechnician = isUserTechnicianList.length > 0;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -101,6 +106,7 @@ export class ConfigComponent implements OnInit {
 | 
			
		||||
        helpVoiceChannelId: this.config.helpVoiceChannelId,
 | 
			
		||||
        teamChannelId: this.config.teamChannelId,
 | 
			
		||||
        loginMessageChannelId: this.config.loginMessageChannelId,
 | 
			
		||||
        featureFlags: this.config.featureFlags,
 | 
			
		||||
        afkChannelIds: this.config.afkChannelIds,
 | 
			
		||||
        moderatorRoleIds: this.config.moderatorRoleIds,
 | 
			
		||||
        adminRoleIds: this.config.adminRoleIds
 | 
			
		||||
@@ -110,7 +116,7 @@ export class ConfigComponent implements OnInit {
 | 
			
		||||
      return throwError(err);
 | 
			
		||||
    })).subscribe(result => {
 | 
			
		||||
      this.spinner.hideSpinner();
 | 
			
		||||
      this.toastService.success(this.translate.instant("view.server.config.message.server#_config_create"), this.translate.instant("view.server.config.message.server_config_create_d"));
 | 
			
		||||
      this.toastService.success(this.translate.instant("view.server.config.message.server_config_create"), this.translate.instant("view.server.config.message.server_config_create_d"));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ export class SidebarService {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async buildMenu(user: UserDTO | null, hasPermission: boolean) {
 | 
			
		||||
  async buildMenu(user: UserDTO | null, hasPermission: boolean, isTechnician: boolean = false) {
 | 
			
		||||
    this.dashboard = {
 | 
			
		||||
      label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "",
 | 
			
		||||
      icon: "pi pi-th-large",
 | 
			
		||||
@@ -127,18 +127,20 @@ export class SidebarService {
 | 
			
		||||
    };
 | 
			
		||||
    this.adminConfig = {
 | 
			
		||||
      label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
 | 
			
		||||
      visible: hasPermission || isTechnician,
 | 
			
		||||
      icon: "pi pi-cog",
 | 
			
		||||
      routerLink: "/admin/settings"
 | 
			
		||||
    };
 | 
			
		||||
    this.adminUsers = {
 | 
			
		||||
      label: this.isSidebarOpen ? this.translateService.instant("sidebar.auth_user_list") : "",
 | 
			
		||||
      visible: hasPermission,
 | 
			
		||||
      icon: "pi pi-user-edit",
 | 
			
		||||
      routerLink: "/admin/users"
 | 
			
		||||
    };
 | 
			
		||||
    this.adminMenu = {
 | 
			
		||||
      label: this.isSidebarOpen ? this.translateService.instant("sidebar.administration") : "",
 | 
			
		||||
      icon: "pi pi-cog",
 | 
			
		||||
      visible: hasPermission,
 | 
			
		||||
      visible: hasPermission || isTechnician,
 | 
			
		||||
      expanded: true,
 | 
			
		||||
      items: [this.adminConfig, this.adminUsers]
 | 
			
		||||
    };
 | 
			
		||||
@@ -148,9 +150,10 @@ export class SidebarService {
 | 
			
		||||
    this.authService.hasUserPermission(AuthRoles.Admin).then(async hasPermission => {
 | 
			
		||||
      let authUser = await this.authService.getLoggedInUser();
 | 
			
		||||
      let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server$.value?.id) ?? null;
 | 
			
		||||
      let isTechnician = authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? [];
 | 
			
		||||
 | 
			
		||||
      if (build || this.menuItems$.value.length == 0) {
 | 
			
		||||
        await this.buildMenu(user, hasPermission);
 | 
			
		||||
        await this.buildMenu(user, hasPermission, isTechnician.length > 0);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.server$.value) {
 | 
			
		||||
@@ -159,7 +162,7 @@ export class SidebarService {
 | 
			
		||||
        this.serverAutoRoles.visible = !!user?.isModerator;
 | 
			
		||||
        this.serverLevels.visible = !!user?.isModerator;
 | 
			
		||||
        this.serverAchievements.visible = !!user?.isModerator;
 | 
			
		||||
        this.serverConfig.visible = !!user?.isAdmin;
 | 
			
		||||
        this.serverConfig.visible = !!user?.isAdmin || isTechnician.length > 0;
 | 
			
		||||
      } else {
 | 
			
		||||
        this.serverMenu.visible = false;
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,7 @@
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "common": {
 | 
			
		||||
    "feature_flags": "Funktionen",
 | 
			
		||||
    "404": "404 - Der Eintrag konnte nicht gefunden werden",
 | 
			
		||||
    "actions": "Aktionen",
 | 
			
		||||
    "active": "Aktiv",
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,6 @@
 | 
			
		||||
    "WebVersion": {
 | 
			
		||||
        "Major": "1",
 | 
			
		||||
        "Minor": "1",
 | 
			
		||||
        "Micro": "dev79_hide_table_columns"
 | 
			
		||||
        "Micro": "dev334_feature_flags_in_wi"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -587,7 +587,7 @@
 | 
			
		||||
 | 
			
		||||
  .p-datatable .p-sortable-column.p-highlight,
 | 
			
		||||
  .p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon,
 | 
			
		||||
  .p-datatable .p-sortable-column:not(.p-highlight):hover{
 | 
			
		||||
  .p-datatable .p-sortable-column:not(.p-highlight):hover {
 | 
			
		||||
    color: $primaryHeaderColor !important;
 | 
			
		||||
    background-color: transparent !important;
 | 
			
		||||
  }
 | 
			
		||||
@@ -672,4 +672,13 @@
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .p-inputswitch.p-inputswitch-checked .p-inputswitch-slider {
 | 
			
		||||
    background: $primaryHeaderColor !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .p-inputswitch.p-focus .p-inputswitch-slider {
 | 
			
		||||
    box-shadow: none !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user