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