Compare commits
	
		
			9 Commits
		
	
	
		
			1.2.2
			...
			34d83a472c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 34d83a472c | |||
| 3fd25418bf | |||
| b175b07e35 | |||
| 06e6d7a0cf | |||
| ec8f15fd72 | |||
| 65a09c428d | |||
| 1125c83d13 | |||
| 76d94c0f60 | |||
| eb3eb24e81 | 
| @@ -24,3 +24,4 @@ class FeatureFlagsEnum(Enum): | ||||
|     game_server = "GameServer" | ||||
|     sync_xp = "SyncXp" | ||||
|     short_role_name = "ShortRoleName" | ||||
|     technician_full_access = "TechnicianFullAccess" | ||||
|   | ||||
| @@ -26,6 +26,7 @@ class FeatureFlagsSettings(ConfigurationModelABC): | ||||
|         FeatureFlagsEnum.game_server.value: False,  # 25.09.2023 #366 | ||||
|         FeatureFlagsEnum.sync_xp.value: False,  # 25.09.2023 #366 | ||||
|         FeatureFlagsEnum.short_role_name.value: False,  # 28.09.2023 #378 | ||||
|         FeatureFlagsEnum.technician_full_access.value: False,  # 02.10.2023 #393 | ||||
|     } | ||||
|  | ||||
|     def __init__(self, **kwargs: dict): | ||||
|   | ||||
| @@ -8,7 +8,6 @@ from bot_data.model.server import Server | ||||
| from bot_data.model.technician_config import TechnicianConfig | ||||
| from bot_data.service.server_config_seeder import ServerConfigSeeder | ||||
| from bot_data.service.technician_config_seeder import TechnicianConfigSeeder | ||||
| from modules.permission.abc.permission_service_abc import PermissionServiceABC | ||||
|  | ||||
|  | ||||
| class ConfigService: | ||||
| @@ -45,6 +44,3 @@ class ConfigService: | ||||
|         self._config.add_configuration( | ||||
|             f"{type(server_config).__name__}_{server_config.server.discord_id}", server_config | ||||
|         ) | ||||
|  | ||||
|         permissions: PermissionServiceABC = self._services.get_service(PermissionServiceABC) | ||||
|         permissions.on_ready() | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| from typing import Callable | ||||
|  | ||||
| from ariadne import ObjectType | ||||
| from cpl_core.configuration import ConfigurationABC | ||||
| from cpl_core.dependency_injection import ServiceProviderABC | ||||
| from cpl_core.type import T | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
| @@ -10,6 +11,7 @@ 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_core.configuration.feature_flags_settings import FeatureFlagsSettings | ||||
| from bot_data.model.achievement import Achievement | ||||
| from bot_data.model.auth_role_enum import AuthRoleEnum | ||||
| from bot_data.model.auth_user import AuthUser | ||||
| @@ -75,7 +77,12 @@ class QueryABC(ObjectType): | ||||
|         def get_services(services: ServiceProviderABC) -> ServiceProviderABC: | ||||
|             return services | ||||
|  | ||||
|         @ServiceProviderABC.inject | ||||
|         def get_config(config: ConfigurationABC) -> ConfigurationABC: | ||||
|             return config | ||||
|  | ||||
|         services = get_services() | ||||
|         config = get_config() | ||||
|         permissions: PermissionService = services.get_service(PermissionService) | ||||
|         bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC) | ||||
|  | ||||
| @@ -84,6 +91,13 @@ class QueryABC(ObjectType): | ||||
|  | ||||
|         for u in user.users: | ||||
|             guild = bot.get_guild(u.server.discord_id) | ||||
|  | ||||
|             settings: ServerConfig = config.get_configuration(f"ServerConfig_{guild.id}") | ||||
|             if not FeatureFlagsSettings.get_flag_from_dict( | ||||
|                 settings.feature_flags, FeatureFlagsEnum.technician_full_access | ||||
|             ): | ||||
|                 continue | ||||
|  | ||||
|             if permissions.is_member_technician(guild.get_member(u.discord_id)): | ||||
|                 return True | ||||
|  | ||||
| @@ -216,23 +230,40 @@ class QueryABC(ObjectType): | ||||
|  | ||||
|     @ServiceProviderABC.inject | ||||
|     def _can_user_mutate_data(self, server: Server, permission: UserRoleEnum, services: ServiceProviderABC): | ||||
|         @ServiceProviderABC.inject | ||||
|         def get_config(config: ConfigurationABC) -> ConfigurationABC: | ||||
|             return config | ||||
|  | ||||
|         config = get_config() | ||||
|         permissions: PermissionService = services.get_service(PermissionService) | ||||
|         bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC) | ||||
|  | ||||
|         auth_user = Route.get_user() | ||||
|         if auth_user == "system" or auth_user.auth_role == AuthRoleEnum.admin: | ||||
|         if auth_user == "system": | ||||
|             return | ||||
|  | ||||
|         member = bot.get_guild(server.discord_id).get_member( | ||||
|             auth_user.users.where(lambda x: x.server.id == server.id).single().discord_id | ||||
|         ) | ||||
|         settings: ServerConfig = config.get_configuration(f"ServerConfig_{member.guild.id}") | ||||
|         technician_full_access_flag = FeatureFlagsSettings.get_flag_from_dict( | ||||
|             settings.feature_flags, FeatureFlagsEnum.technician_full_access | ||||
|         ) | ||||
|  | ||||
|         check_perm = lambda x: True | ||||
|         check_perm = lambda x: False | ||||
|         match permission: | ||||
|             case UserRoleEnum.moderator: | ||||
|                 check_perm = lambda x: permissions.is_member_moderator(x) | ||||
|                 check_perm = ( | ||||
|                     lambda x: technician_full_access_flag | ||||
|                     and permissions.is_member_technician(x) | ||||
|                     or permissions.is_member_moderator(x) | ||||
|                 ) | ||||
|             case UserRoleEnum.admin: | ||||
|                 check_perm = lambda x: permissions.is_member_admin(x) | ||||
|                 check_perm = ( | ||||
|                     lambda x: technician_full_access_flag | ||||
|                     and permissions.is_member_technician(x) | ||||
|                     or permissions.is_member_admin(x) | ||||
|                 ) | ||||
|             case UserRoleEnum.technician: | ||||
|                 check_perm = lambda x: permissions.is_member_technician(x) | ||||
|  | ||||
|   | ||||
| @@ -183,4 +183,3 @@ class ServerConfigMutation(QueryABC): | ||||
|             self._server_configs.add_server_team_role_id_config(role_id) | ||||
|  | ||||
|         self._bot.loop.create_task(self._config_service.reload_server_config(new_config.server)) | ||||
|         self._permissions.on_ready() | ||||
|   | ||||
| @@ -12,7 +12,6 @@ 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): | ||||
| @@ -23,7 +22,6 @@ class TechnicianConfigMutation(QueryABC): | ||||
|         servers: ServerRepositoryABC, | ||||
|         technician_configs: TechnicianConfigRepositoryABC, | ||||
|         db: DatabaseContextABC, | ||||
|         permissions: PermissionServiceABC, | ||||
|         config_service: ConfigService, | ||||
|     ): | ||||
|         QueryABC.__init__(self, "TechnicianConfigMutation") | ||||
| @@ -33,7 +31,6 @@ 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) | ||||
| @@ -114,4 +111,3 @@ class TechnicianConfigMutation(QueryABC): | ||||
|             self._technician_configs.add_technician_id_config(TechnicianIdConfig(technician_id)) | ||||
|  | ||||
|         self._bot.loop.create_task(self._config_service.reload_technician_config()) | ||||
|         self._permissions.on_ready() | ||||
|   | ||||
| @@ -8,42 +8,14 @@ class PermissionServiceABC(ABC): | ||||
|     def __init__(self): | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def on_ready(self): | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def on_member_update(self, before: discord.Member, after: discord.Member): | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_admin_role_ids(self, g_id: int) -> list[int]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_admin_roles(self, g_id: int) -> list[discord.Role]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_admins(self, g_id: int) -> list[discord.Member]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_moderator_role_ids(self, g_id: int) -> list[int]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_moderator_roles(self, g_id: int) -> list[discord.Role]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_moderators(self, g_id: int) -> list[discord.Member]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def get_technicians(self) -> list[discord.Member]: | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def is_member_admin(self, member: discord.Member) -> bool: | ||||
|         pass | ||||
|   | ||||
| @@ -1,26 +0,0 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
| bot sh-edraft.de Discord bot | ||||
| ~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| Discord bot for customers of sh-edraft.de | ||||
|  | ||||
| :copyright: (c) 2022 - 2023 sh-edraft.de | ||||
| :license: MIT, see LICENSE for more details. | ||||
|  | ||||
| """ | ||||
|  | ||||
| __title__ = "modules.permission.events" | ||||
| __author__ = "Sven Heidemann" | ||||
| __license__ = "MIT" | ||||
| __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" | ||||
| __version__ = "1.1.9" | ||||
|  | ||||
| from collections import namedtuple | ||||
|  | ||||
|  | ||||
| # imports: | ||||
|  | ||||
| VersionInfo = namedtuple("VersionInfo", "major minor micro") | ||||
| version_info = VersionInfo(major="1", minor="1", micro="9") | ||||
| @@ -1,30 +0,0 @@ | ||||
| import discord | ||||
| from cpl_core.configuration import ConfigurationABC | ||||
| from cpl_core.logging import LoggerABC | ||||
| from cpl_discord.events import OnMemberUpdateABC | ||||
|  | ||||
| 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 | ||||
| from modules.permission.abc.permission_service_abc import PermissionServiceABC | ||||
|  | ||||
|  | ||||
| class PermissionOnMemberUpdateEvent(OnMemberUpdateABC): | ||||
|     def __init__(self, config: ConfigurationABC, logger: LoggerABC, permission_service: PermissionServiceABC): | ||||
|         OnMemberUpdateABC.__init__(self) | ||||
|         self._config = config | ||||
|         self._logger = logger | ||||
|         self._permission_service = permission_service | ||||
|  | ||||
|     async def on_member_update(self, before: discord.Member, after: discord.Member): | ||||
|         if before.guild is not None: | ||||
|             server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{before.guild.id}") | ||||
|             if not FeatureFlagsSettings.get_flag_from_dict( | ||||
|                 server_config.feature_flags, FeatureFlagsEnum.permission_module | ||||
|             ): | ||||
|                 return | ||||
|  | ||||
|         self._logger.debug(__name__, f"Module {type(self)} started") | ||||
|  | ||||
|         if before.roles != after.roles: | ||||
|             self._permission_service.on_member_update(before, after) | ||||
| @@ -1,22 +0,0 @@ | ||||
| from cpl_core.logging import LoggerABC | ||||
| from cpl_discord.events import OnReadyABC | ||||
|  | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
| from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings | ||||
| from bot_data.model.technician_config import TechnicianConfig | ||||
| from modules.permission.abc.permission_service_abc import PermissionServiceABC | ||||
|  | ||||
|  | ||||
| class PermissionOnReadyEvent(OnReadyABC): | ||||
|     def __init__(self, logger: LoggerABC, permission_service: PermissionServiceABC, tech_config: TechnicianConfig): | ||||
|         OnReadyABC.__init__(self) | ||||
|         self._logger = logger | ||||
|         self._permission_service = permission_service | ||||
|         self._tech_config = tech_config | ||||
|  | ||||
|     async def on_ready(self): | ||||
|         if not FeatureFlagsSettings.get_flag_from_dict( | ||||
|             self._tech_config.feature_flags, FeatureFlagsEnum.permission_module | ||||
|         ): | ||||
|             return | ||||
|         self._permission_service.on_ready() | ||||
| @@ -1,16 +1,11 @@ | ||||
| from cpl_core.configuration import ConfigurationABC | ||||
| from cpl_core.dependency_injection import ServiceCollectionABC | ||||
| from cpl_core.environment import ApplicationEnvironmentABC | ||||
| from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum | ||||
| from cpl_discord.service.discord_collection_abc import DiscordCollectionABC | ||||
|  | ||||
| from bot_core.abc.module_abc import ModuleABC | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
| from modules.permission.abc.permission_service_abc import PermissionServiceABC | ||||
| from modules.permission.events.permission_on_member_update_event import ( | ||||
|     PermissionOnMemberUpdateEvent, | ||||
| ) | ||||
| from modules.permission.events.permission_on_ready_event import PermissionOnReadyEvent | ||||
| from modules.permission.service.permission_service import PermissionService | ||||
|  | ||||
|  | ||||
| @@ -25,5 +20,3 @@ class PermissionModule(ModuleABC): | ||||
|         services.add_singleton(PermissionServiceABC, PermissionService) | ||||
|         # commands | ||||
|         # events | ||||
|         self._dc.add_event(DiscordEventTypesEnum.on_ready.value, PermissionOnReadyEvent) | ||||
|         self._dc.add_event(DiscordEventTypesEnum.on_member_update.value, PermissionOnMemberUpdateEvent) | ||||
|   | ||||
| @@ -3,146 +3,55 @@ from cpl_core.configuration import ConfigurationABC | ||||
| from cpl_core.logging import LoggerABC | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
|  | ||||
| from bot_data.model.server_config import ServerConfig | ||||
| from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC | ||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC | ||||
| from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC | ||||
| 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.technician_config import TechnicianConfig | ||||
| from modules.permission.abc.permission_service_abc import PermissionServiceABC | ||||
|  | ||||
|  | ||||
| class PermissionService(PermissionServiceABC): | ||||
|     def __init__( | ||||
|         self, | ||||
|         technician_settings: TechnicianConfig, | ||||
|         logger: LoggerABC, | ||||
|         bot: DiscordBotServiceABC, | ||||
|         config: ConfigurationABC, | ||||
|         servers: ServerRepositoryABC, | ||||
|         server_configs: ServerConfigRepositoryABC, | ||||
|         technician_configs: TechnicianConfigRepositoryABC, | ||||
|     ): | ||||
|         PermissionServiceABC.__init__(self) | ||||
|         self._logger = logger | ||||
|         self._bot = bot | ||||
|         self._config = config | ||||
|         self._technician_settings = technician_settings | ||||
|         self._servers = servers | ||||
|         self._server_configs = server_configs | ||||
|         self._technician_configs = technician_configs | ||||
|  | ||||
|         self._admin_role_ids: dict[int, list[int]] = {} | ||||
|         self._admin_roles: dict[int, list[discord.Role]] = {} | ||||
|         self._admins: dict[int, list[discord.Member]] = {} | ||||
|     def _team_role_members(self, guild_id: int, team_role_type: TeamMemberTypeEnum): | ||||
|         guild = self._bot.get_guild(guild_id) | ||||
|         server = self._servers.get_server_by_discord_id(guild_id) | ||||
|         config = self._server_configs.get_server_config_by_server(server.id) | ||||
|         admins = [] | ||||
|         for role_id in config.team_role_ids.where(lambda x: x.team_member_type == team_role_type): | ||||
|             role_id: ServerTeamRoleIdsConfig = role_id | ||||
|             admins = guild.get_role(role_id.role_id).members | ||||
|  | ||||
|         self._moderator_role_ids: dict[int, list[int]] = {} | ||||
|         self._moderator_roles: dict[int, list[discord.Role]] = {} | ||||
|         self._moderators: dict[int, list[discord.Member]] = {} | ||||
|  | ||||
|         self._technician_ids: list[int] = technician_settings.technician_ids.to_list() | ||||
|         self._technicians: list[discord.Member] = [] | ||||
|  | ||||
|     def on_ready(self): | ||||
|         for guild in self._bot.guilds: | ||||
|             guild: discord.Guild = guild | ||||
|             self._logger.debug(__name__, f"Validate permission settings") | ||||
|  | ||||
|             for technician_id in self._technician_ids: | ||||
|                 technician = guild.get_member(technician_id) | ||||
|                 if technician is None: | ||||
|                     continue | ||||
|                 self._technicians.append(technician) | ||||
|  | ||||
|             settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}") | ||||
|             if settings is None: | ||||
|                 self._logger.error(__name__, "Server settings not found") | ||||
|                 return | ||||
|  | ||||
|             self._admin_role_ids[guild.id] = ( | ||||
|                 settings.team_role_ids.where(lambda x: x.team_member_type == TeamMemberTypeEnum.admin) | ||||
|                 .select(lambda x: x.role_id) | ||||
|                 .to_list() | ||||
|             ) | ||||
|             self._moderator_role_ids[guild.id] = ( | ||||
|                 settings.team_role_ids.where(lambda x: x.team_member_type == TeamMemberTypeEnum.moderator) | ||||
|                 .select(lambda x: x.role_id) | ||||
|                 .to_list() | ||||
|             ) | ||||
|  | ||||
|             admin_roles = [] | ||||
|             admins = [] | ||||
|  | ||||
|             mod_roles = [] | ||||
|             mods = [] | ||||
|  | ||||
|             for role in guild.roles: | ||||
|                 role: discord.Role = role | ||||
|  | ||||
|                 if role.id in self._admin_role_ids[guild.id]: | ||||
|                     admin_roles.append(role) | ||||
|                     self._logger.trace(__name__, f"Added admin role {role}") | ||||
|  | ||||
|                     for member in role.members: | ||||
|                         admins.append(member) | ||||
|                         self._logger.trace(__name__, f"Added admin {member}") | ||||
|  | ||||
|                 if role.id in self._moderator_role_ids[guild.id]: | ||||
|                     mod_roles.append(role) | ||||
|                     self._logger.trace(__name__, f"Added moderator role {role}") | ||||
|  | ||||
|                     for member in role.members: | ||||
|                         mods.append(member) | ||||
|                         self._logger.trace(__name__, f"Added moderator {member}") | ||||
|  | ||||
|             self._admin_roles[guild.id] = admin_roles | ||||
|             self._admins[guild.id] = admins | ||||
|             self._moderator_roles[guild.id] = mod_roles | ||||
|             self._moderators[guild.id] = mods | ||||
|  | ||||
|     def on_member_update(self, before: discord.Member, after: discord.Member): | ||||
|         g_id = after.guild.id | ||||
|  | ||||
|         for admin_role in self._admin_roles[g_id]: | ||||
|             if admin_role in before.roles and admin_role not in after.roles: | ||||
|                 self._admins[g_id].remove(after) | ||||
|                 self._logger.trace(__name__, f"Removed {after.id} from admins") | ||||
|  | ||||
|             elif admin_role in after.roles and admin_role not in before.roles: | ||||
|                 self._admins[g_id].append(after) | ||||
|                 self._logger.trace(__name__, f"Added {after.id} to admins") | ||||
|  | ||||
|         for moderator_role in self._moderator_roles[g_id]: | ||||
|             if moderator_role in before.roles and moderator_role not in after.roles: | ||||
|                 self._moderators[g_id].remove(after) | ||||
|                 self._logger.trace(__name__, f"Removed {after.id} from moderators") | ||||
|  | ||||
|             elif moderator_role in after.roles and moderator_role not in before.roles: | ||||
|                 self._moderators[g_id].append(after) | ||||
|                 self._logger.trace(__name__, f"Added {after.id} to moderators") | ||||
|  | ||||
|     def get_admin_role_ids(self, g_id: int) -> list[int]: | ||||
|         return self._admin_role_ids[g_id] | ||||
|  | ||||
|     def get_admin_roles(self, g_id: int) -> list[discord.Role]: | ||||
|         return self._admin_roles[g_id] | ||||
|         return admins | ||||
|  | ||||
|     def get_admins(self, g_id: int) -> list[discord.Member]: | ||||
|         return self._admins[g_id] | ||||
|  | ||||
|     def get_moderator_role_ids(self, g_id: int) -> list[int]: | ||||
|         return self._moderator_role_ids[g_id] | ||||
|  | ||||
|     def get_moderator_roles(self, g_id: int) -> list[discord.Role]: | ||||
|         return self._moderator_roles[g_id] | ||||
|         return self._team_role_members(g_id, TeamMemberTypeEnum.admin) | ||||
|  | ||||
|     def get_moderators(self, g_id: int) -> list[discord.Member]: | ||||
|         return self._moderators[g_id] | ||||
|  | ||||
|     def get_technicians(self) -> list[discord.Member]: | ||||
|         return self._technicians | ||||
|         return self._team_role_members(g_id, TeamMemberTypeEnum.moderator) | ||||
|  | ||||
|     def is_member_admin(self, member: discord.Member) -> bool: | ||||
|         return member is not None and member.guild.id in self._admins and member in self._admins[member.guild.id] | ||||
|         return member in self.get_admins(member.guild.id) | ||||
|  | ||||
|     def is_member_moderator(self, member: discord.Member) -> bool: | ||||
|         return ( | ||||
|             member is not None | ||||
|             and member.guild.id in self._moderators | ||||
|             and member in self._moderators[member.guild.id] | ||||
|             or self.is_member_admin(member) | ||||
|         ) | ||||
|         return member in self.get_admins(member.guild.id) or member in self.get_moderators(member.guild.id) | ||||
|  | ||||
|     def is_member_technician(self, member: discord.Member) -> bool: | ||||
|         return member is not None and member in self._technicians | ||||
|         config = self._technician_configs.get_technician_config() | ||||
|         return str(member.id) in config.technician_ids.select(lambda x: str(x)) | ||||
|   | ||||
| @@ -51,4 +51,4 @@ | ||||
|         "tslib": "^2.4.1", | ||||
|         "typescript": "~4.9.5" | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -50,10 +50,14 @@ export class AuthGuard implements CanActivate { | ||||
|     if (memberRole !== undefined) { | ||||
|       let userHasAccess = false; | ||||
|       let authUser = await this.authService.getLoggedInUser(); | ||||
|       let isTechnician = (authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? []).length > 0; | ||||
|       if (isTechnician) { | ||||
|         return true; | ||||
|       } | ||||
|       let server = route.params["serverId"]; | ||||
|  | ||||
|       if (!authUser || !authUser.users) { | ||||
|         return true; | ||||
|         return false; | ||||
|       } | ||||
|       authUser?.users?.forEach(u => { | ||||
|         if (u.server === +(server ?? 0)) { | ||||
|   | ||||
| @@ -48,7 +48,7 @@ export class ProfileComponent implements OnInit, OnDestroy { | ||||
|         let authUser = await this.auth.getLoggedInUser(); | ||||
|         this.spinner.showSpinner(); | ||||
|         let user: UserDTO | null = authUser?.users?.find(u => u.server == server.id) ?? null; | ||||
|         if (!user || user?.id != params["memberId"] && !user?.isModerator) { | ||||
|         if (!user || user?.id != params["memberId"] && !user?.isModerator && !user.isModerator) { | ||||
|           this.toast.error(this.translate.instant("view.server.profile.permission_denied"), this.translate.instant("view.server.profile.permission_denied_d")); | ||||
|           this.spinner.hideSpinner(); | ||||
|           await this.router.navigate(["/server", server.id]); | ||||
|   | ||||
| @@ -86,7 +86,7 @@ export class ShortRoleNamesComponent extends ComponentWithTable implements OnIni | ||||
|  | ||||
|       this.spinner.showSpinner(); | ||||
|       this.data.query<SingleDiscordQuery>(Queries.guildsQuery, { | ||||
|           id: server?.discordId | ||||
|           id: server?.discordId ?? 0 | ||||
|         } | ||||
|       ).subscribe(data => { | ||||
|         if (data.discord.guilds) { | ||||
|   | ||||
| @@ -15,216 +15,216 @@ import { DataService } from "../data/data.service"; | ||||
| import { FeatureFlag } from "../../models/config/feature-flags.model"; | ||||
|  | ||||
| @Injectable({ | ||||
|     providedIn: "root" | ||||
|   providedIn: "root" | ||||
| }) | ||||
| export class SidebarService { | ||||
|  | ||||
|     isSidebarOpen: boolean = true; | ||||
|     menuItems$ = new BehaviorSubject<MenuItem[]>(new Array<MenuItem>()); | ||||
|     server!: Server | undefined; | ||||
|   isSidebarOpen: boolean = true; | ||||
|   menuItems$ = new BehaviorSubject<MenuItem[]>(new Array<MenuItem>()); | ||||
|   server!: Server | undefined; | ||||
|  | ||||
|     dashboard: MenuItem = {}; | ||||
|     serverDashboard: MenuItem = {}; | ||||
|     serverProfile: MenuItem = {}; | ||||
|     serverMembers: MenuItem = {}; | ||||
|     serverAutoRoles: MenuItem = {}; | ||||
|     serverLevels: MenuItem = {}; | ||||
|     serverAchievements: MenuItem = {}; | ||||
|     serverShortRoleNames: MenuItem = {}; | ||||
|     serverConfig: MenuItem = {}; | ||||
|     serverMenu: MenuItem = {}; | ||||
|     adminConfig: MenuItem = {}; | ||||
|     adminUsers: MenuItem = {}; | ||||
|     adminMenu: MenuItem = {}; | ||||
|   dashboard: MenuItem = {}; | ||||
|   serverDashboard: MenuItem = {}; | ||||
|   serverProfile: MenuItem = {}; | ||||
|   serverMembers: MenuItem = {}; | ||||
|   serverAutoRoles: MenuItem = {}; | ||||
|   serverLevels: MenuItem = {}; | ||||
|   serverAchievements: MenuItem = {}; | ||||
|   serverShortRoleNames: MenuItem = {}; | ||||
|   serverConfig: MenuItem = {}; | ||||
|   serverMenu: MenuItem = {}; | ||||
|   adminConfig: MenuItem = {}; | ||||
|   adminUsers: MenuItem = {}; | ||||
|   adminMenu: MenuItem = {}; | ||||
|  | ||||
|     featureFlags: FeatureFlag[] = []; | ||||
|   featureFlags: FeatureFlag[] = []; | ||||
|  | ||||
|     constructor( | ||||
|         private themeService: ThemeService, | ||||
|         private authService: AuthService, | ||||
|         private translateService: TranslateService, | ||||
|         private router: Router, | ||||
|         private serverService: ServerService, | ||||
|         private data: DataService | ||||
|     ) { | ||||
|         this.themeService.isSidebarOpen$.subscribe(value => { | ||||
|             this.isSidebarOpen = value; | ||||
|             this.setMenu(true); | ||||
|   constructor( | ||||
|     private themeService: ThemeService, | ||||
|     private authService: AuthService, | ||||
|     private translateService: TranslateService, | ||||
|     private router: Router, | ||||
|     private serverService: ServerService, | ||||
|     private data: DataService | ||||
|   ) { | ||||
|     this.themeService.isSidebarOpen$.subscribe(value => { | ||||
|       this.isSidebarOpen = value; | ||||
|       this.setMenu(true); | ||||
|     }); | ||||
|  | ||||
|     this.translateService.onLangChange.subscribe(_ => { | ||||
|       this.setMenu(true); | ||||
|     }); | ||||
|  | ||||
|     this.serverService.server$.subscribe(server => { | ||||
|       this.server = server; | ||||
|       if (server) { | ||||
|         this.setMenu(true); | ||||
|       } else { | ||||
|         this.setMenu(false); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   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", | ||||
|       routerLink: "dashboard" | ||||
|     }; | ||||
|     this.serverDashboard = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.dashboard") : "", | ||||
|       icon: "pi pi-th-large", | ||||
|       routerLink: `server/${this.server?.id}` | ||||
|     }; | ||||
|     this.serverProfile = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.profile") : "", | ||||
|       icon: "pi pi-id-card", | ||||
|       routerLink: `server/${this.server?.id}/members/${user?.id}` | ||||
|     }; | ||||
|     this.serverMembers = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.members") : "", | ||||
|       icon: "pi pi-users", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server?.id}/members` | ||||
|     }; | ||||
|  | ||||
|     this.serverAutoRoles = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.auto_roles") : "", | ||||
|       icon: "pi pi-sitemap", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server?.id}/auto-roles` | ||||
|     }; | ||||
|  | ||||
|     this.serverLevels = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.levels") : "", | ||||
|       icon: "pi pi-book", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server?.id}/levels` | ||||
|     }; | ||||
|  | ||||
|     this.serverAchievements = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.achievements") : "", | ||||
|       icon: "pi pi-angle-double-up", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server?.id}/achievements` | ||||
|     }; | ||||
|  | ||||
|     this.serverShortRoleNames = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.short_role_names") : "", | ||||
|       icon: "pi pi-list", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server?.id}/short-role-names` | ||||
|     }; | ||||
|  | ||||
|     this.serverConfig = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.configuration") : "", | ||||
|       icon: "pi pi-cog", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server?.id}/config` | ||||
|     }; | ||||
|  | ||||
|     this.serverMenu = { | ||||
|       label: this.isSidebarOpen ? this.server?.name : "", | ||||
|       icon: "pi pi-server", | ||||
|       visible: false, | ||||
|       expanded: true, | ||||
|       items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverShortRoleNames, this.serverConfig] | ||||
|     }; | ||||
|     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 || isTechnician, | ||||
|       expanded: true, | ||||
|       items: [this.adminConfig, this.adminUsers] | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   setMenu(build: boolean = false) { | ||||
|     const server = this.server; | ||||
|  | ||||
|     if (server) { | ||||
|       this.featureFlags = []; | ||||
|       this.data.query<PossibleFeatureFlagsQuery>("{possibleFeatureFlags}" | ||||
|       ).subscribe(data => { | ||||
|         let observables: Observable<HasServerFeatureFlagQuery>[] = []; | ||||
|         data.possibleFeatureFlags.forEach(flag => { | ||||
|           observables.push( | ||||
|             this.data.query<HasServerFeatureFlagQuery>(Queries.hasServerFeatureFlag, { | ||||
|                 filter: { id: server.id }, | ||||
|                 flag: flag | ||||
|               }, | ||||
|               function(data: Query) { | ||||
|                 return data.servers[0]; | ||||
|               } | ||||
|             ) | ||||
|           ); | ||||
|         }); | ||||
|  | ||||
|         this.translateService.onLangChange.subscribe(_ => { | ||||
|             this.setMenu(true); | ||||
|         }); | ||||
|  | ||||
|         this.serverService.server$.subscribe(server => { | ||||
|             this.server = server; | ||||
|             if (server) { | ||||
|                 this.setMenu(true); | ||||
|             } else { | ||||
|                 this.setMenu(false); | ||||
|         forkJoin(observables).subscribe(data => { | ||||
|           data.forEach(flag => { | ||||
|             if (!flag.hasFeatureFlag.value) { | ||||
|               return; | ||||
|             } | ||||
|             this.featureFlags.push(flag.hasFeatureFlag); | ||||
|           }); | ||||
|           this._setMenu(build); | ||||
|         }); | ||||
|       }); | ||||
|     } else { | ||||
|       this._setMenu(build); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|     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", | ||||
|             routerLink: "dashboard" | ||||
|         }; | ||||
|         this.serverDashboard = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.dashboard") : "", | ||||
|             icon: "pi pi-th-large", | ||||
|             routerLink: `server/${this.server?.id}` | ||||
|         }; | ||||
|         this.serverProfile = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.profile") : "", | ||||
|             icon: "pi pi-id-card", | ||||
|             routerLink: `server/${this.server?.id}/members/${user?.id}` | ||||
|         }; | ||||
|         this.serverMembers = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.members") : "", | ||||
|             icon: "pi pi-users", | ||||
|             visible: true, | ||||
|             routerLink: `server/${this.server?.id}/members` | ||||
|         }; | ||||
|   private _setMenu(build: boolean = false) { | ||||
|     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?.id) ?? null; | ||||
|       let isTechnician = (authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? []).length > 0; | ||||
|  | ||||
|         this.serverAutoRoles = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.auto_roles") : "", | ||||
|             icon: "pi pi-sitemap", | ||||
|             visible: true, | ||||
|             routerLink: `server/${this.server?.id}/auto-roles` | ||||
|         }; | ||||
|       if (build || this.menuItems$.value.length == 0) { | ||||
|         await this.buildMenu(user, hasPermission, isTechnician); | ||||
|       } | ||||
|  | ||||
|         this.serverLevels = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.levels") : "", | ||||
|             icon: "pi pi-book", | ||||
|             visible: true, | ||||
|             routerLink: `server/${this.server?.id}/levels` | ||||
|         }; | ||||
|       if (this.server) { | ||||
|         this.serverMenu.visible = true; | ||||
|         this.serverMembers.visible = this.hasFeature("TechnicianFullAccess") && isTechnician || user?.isModerator; | ||||
|         this.serverAutoRoles.visible = this.hasFeature("TechnicianFullAccess") && isTechnician || this.hasFeature("AutoRoleModule") && user?.isModerator; | ||||
|         this.serverLevels.visible = this.hasFeature("TechnicianFullAccess") && isTechnician || this.hasFeature("LevelModule") && user?.isModerator; | ||||
|         this.serverAchievements.visible = this.hasFeature("TechnicianFullAccess") && isTechnician || this.hasFeature("AchievementsModule") && user?.isModerator; | ||||
|         this.serverShortRoleNames.visible = this.hasFeature("TechnicianFullAccess") && isTechnician || this.hasFeature("ShortRoleName") && user?.isAdmin; | ||||
|  | ||||
|         this.serverAchievements = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.achievements") : "", | ||||
|             icon: "pi pi-angle-double-up", | ||||
|             visible: true, | ||||
|             routerLink: `server/${this.server?.id}/achievements` | ||||
|         }; | ||||
|         this.serverConfig.visible = isTechnician || user?.isAdmin; | ||||
|       } else { | ||||
|         this.serverMenu.visible = false; | ||||
|       } | ||||
|  | ||||
|         this.serverShortRoleNames = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.short_role_names") : "", | ||||
|             icon: "pi pi-list", | ||||
|             visible: true, | ||||
|             routerLink: `server/${this.server?.id}/short-role-names` | ||||
|         }; | ||||
|       let menuItems: MenuItem[] = [ | ||||
|         this.dashboard, | ||||
|         this.serverMenu, | ||||
|         this.adminMenu | ||||
|       ]; | ||||
|       this.menuItems$.next(menuItems); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|         this.serverConfig = { | ||||
|             label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.configuration") : "", | ||||
|             icon: "pi pi-cog", | ||||
|             visible: true, | ||||
|             routerLink: `server/${this.server?.id}/config` | ||||
|         }; | ||||
|  | ||||
|         this.serverMenu = { | ||||
|             label: this.isSidebarOpen ? this.server?.name : "", | ||||
|             icon: "pi pi-server", | ||||
|             visible: false, | ||||
|             expanded: true, | ||||
|             items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverShortRoleNames, this.serverConfig] | ||||
|         }; | ||||
|         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 || isTechnician, | ||||
|             expanded: true, | ||||
|             items: [this.adminConfig, this.adminUsers] | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     setMenu(build: boolean = false) { | ||||
|         const server = this.server; | ||||
|  | ||||
|         if (server) { | ||||
|             this.featureFlags = []; | ||||
|             this.data.query<PossibleFeatureFlagsQuery>("{possibleFeatureFlags}" | ||||
|             ).subscribe(data => { | ||||
|                 let observables: Observable<HasServerFeatureFlagQuery>[] = []; | ||||
|                 data.possibleFeatureFlags.forEach(flag => { | ||||
|                     observables.push( | ||||
|                         this.data.query<HasServerFeatureFlagQuery>(Queries.hasServerFeatureFlag, { | ||||
|                                 filter: { id: server.id }, | ||||
|                                 flag: flag | ||||
|                             }, | ||||
|                             function(data: Query) { | ||||
|                                 return data.servers[0]; | ||||
|                             } | ||||
|                         ) | ||||
|                     ); | ||||
|                 }); | ||||
|  | ||||
|                 forkJoin(observables).subscribe(data => { | ||||
|                     data.forEach(flag => { | ||||
|                         if (!flag.hasFeatureFlag.value) { | ||||
|                             return; | ||||
|                         } | ||||
|                         this.featureFlags.push(flag.hasFeatureFlag); | ||||
|                     }); | ||||
|                     this._setMenu(build); | ||||
|                 }); | ||||
|             }); | ||||
|         } else { | ||||
|             this._setMenu(build); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private _setMenu(build: boolean = false) { | ||||
|         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?.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, isTechnician.length > 0); | ||||
|             } | ||||
|  | ||||
|             if (this.server) { | ||||
|                 this.serverMenu.visible = true; | ||||
|                 this.serverMembers.visible = !!user?.isModerator; | ||||
|                 this.serverAutoRoles.visible = this.hasFeature("AutoRoleModule") ? !!user?.isModerator : false; | ||||
|                 this.serverLevels.visible = this.hasFeature("LevelModule") ? !!user?.isModerator : false; | ||||
|                 this.serverAchievements.visible = this.hasFeature("AchievementsModule") ? !!user?.isModerator : false; | ||||
|                 this.serverShortRoleNames.visible = this.hasFeature("ShortRoleName") ? !!user?.isAdmin : false; | ||||
|  | ||||
|                 this.serverConfig.visible = !!user?.isAdmin || isTechnician.length > 0; | ||||
|             } else { | ||||
|                 this.serverMenu.visible = false; | ||||
|             } | ||||
|  | ||||
|             let menuItems: MenuItem[] = [ | ||||
|                 this.dashboard, | ||||
|                 this.serverMenu, | ||||
|                 this.adminMenu | ||||
|             ]; | ||||
|             this.menuItems$.next(menuItems); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     private hasFeature(key: string): boolean { | ||||
|         const flag = this.featureFlags.filter(flag => flag.key == key); | ||||
|         if (flag.length == 0) { | ||||
|             return false; | ||||
|         } | ||||
|         return flag[0].value; | ||||
|   private hasFeature(key: string): boolean { | ||||
|     const flag = this.featureFlags.filter(flag => flag.key == key); | ||||
|     if (flag.length == 0) { | ||||
|       return false; | ||||
|     } | ||||
|     return flag[0].value; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "WebVersion": { | ||||
|     "Major": "1", | ||||
|     "Minor": "1", | ||||
|     "Micro": "9" | ||||
|   } | ||||
| } | ||||
|     "WebVersion": { | ||||
|         "Major": "1", | ||||
|         "Minor": "1", | ||||
|         "Micro": "9" | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user