From ba633be0347304aea180e64bfd69baa4d98a99f7 Mon Sep 17 00:00:00 2001 From: Amos Date: Sun, 30 Jun 2024 03:50:00 +0100 Subject: [PATCH] Refactor MuteManager constructor and clean up code (#329) The MuteManager constructor within the Mute plugin has been refactored for better dependency injection. This change simplifies the class construction by directly initializing fields in the constructor parameters. Additionally, several minor code improvements have been made, including spelling corrections and replacing some conditional checks for readability. Other arrays or methods in the plugin are also revised for better maintainability and readability of the code. --- Plugins/Mute/Commands/MuteCommand.cs | 6 +- Plugins/Mute/Commands/MuteInfoCommand.cs | 6 +- Plugins/Mute/Commands/TempMuteCommand.cs | 16 ++-- Plugins/Mute/Commands/UnmuteCommand.cs | 6 +- Plugins/Mute/Mute.csproj | 1 + Plugins/Mute/MuteManager.cs | 30 +++----- Plugins/Mute/Plugin.cs | 95 +++++++++++++++--------- 7 files changed, 89 insertions(+), 71 deletions(-) diff --git a/Plugins/Mute/Commands/MuteCommand.cs b/Plugins/Mute/Commands/MuteCommand.cs index 82c4cd7e2..0e894f542 100644 --- a/Plugins/Mute/Commands/MuteCommand.cs +++ b/Plugins/Mute/Commands/MuteCommand.cs @@ -20,8 +20,8 @@ public MuteCommand(CommandConfiguration config, ITranslationLookup translationLo Permission = EFClient.Permission.Moderator; RequiresTarget = true; SupportedGames = Plugin.SupportedGames; - Arguments = new[] - { + Arguments = + [ new CommandArgument { Name = translationLookup["COMMANDS_ARGS_PLAYER"], @@ -32,7 +32,7 @@ public MuteCommand(CommandConfiguration config, ITranslationLookup translationLo Name = translationLookup["COMMANDS_ARGS_REASON"], Required = true } - }; + ]; } public override async Task ExecuteAsync(GameEvent gameEvent) diff --git a/Plugins/Mute/Commands/MuteInfoCommand.cs b/Plugins/Mute/Commands/MuteInfoCommand.cs index 4622a0ce9..bba01a9e7 100644 --- a/Plugins/Mute/Commands/MuteInfoCommand.cs +++ b/Plugins/Mute/Commands/MuteInfoCommand.cs @@ -21,14 +21,14 @@ public MuteInfoCommand(CommandConfiguration config, ITranslationLookup translati Permission = EFClient.Permission.Moderator; RequiresTarget = true; SupportedGames = Plugin.SupportedGames; - Arguments = new[] - { + Arguments = + [ new CommandArgument { Name = translationLookup["COMMANDS_ARGS_PLAYER"], Required = true } - }; + ]; } public override async Task ExecuteAsync(GameEvent gameEvent) diff --git a/Plugins/Mute/Commands/TempMuteCommand.cs b/Plugins/Mute/Commands/TempMuteCommand.cs index 69a2999c9..9275b1075 100644 --- a/Plugins/Mute/Commands/TempMuteCommand.cs +++ b/Plugins/Mute/Commands/TempMuteCommand.cs @@ -7,10 +7,9 @@ namespace IW4MAdmin.Plugins.Mute.Commands; -public class TempMuteCommand : Command +public partial class TempMuteCommand : Command { private readonly MuteManager _muteManager; - private const string TempBanRegex = @"([0-9]+\w+)\ (.+)"; public TempMuteCommand(CommandConfiguration config, ITranslationLookup translationLookup, MuteManager muteManager) : base(config, translationLookup) @@ -22,8 +21,8 @@ public TempMuteCommand(CommandConfiguration config, ITranslationLookup translati Permission = EFClient.Permission.Moderator; RequiresTarget = true; SupportedGames = Plugin.SupportedGames; - Arguments = new[] - { + Arguments = + [ new CommandArgument { Name = translationLookup["COMMANDS_ARGS_PLAYER"], @@ -39,7 +38,7 @@ public TempMuteCommand(CommandConfiguration config, ITranslationLookup translati Name = translationLookup["COMMANDS_ARGS_REASON"], Required = true } - }; + ]; } public override async Task ExecuteAsync(GameEvent gameEvent) @@ -49,8 +48,8 @@ public override async Task ExecuteAsync(GameEvent gameEvent) gameEvent.Origin.Tell(_translationLookup["COMMANDS_DENY_SELF_TARGET"]); return; } - - var match = Regex.Match(gameEvent.Data, TempBanRegex); + + var match = TempBanRegex().Match(gameEvent.Data); if (match.Success) { var expiration = DateTime.UtcNow + match.Groups[1].ToString().ParseTimespan(); @@ -72,4 +71,7 @@ public override async Task ExecuteAsync(GameEvent gameEvent) gameEvent.Origin.Tell(_translationLookup["PLUGINS_MUTE_COMMANDS_TEMPMUTE_BAD_FORMAT"]); } + + [GeneratedRegex(@"([0-9]+\w+)\ (.+)")] + private static partial Regex TempBanRegex(); } diff --git a/Plugins/Mute/Commands/UnmuteCommand.cs b/Plugins/Mute/Commands/UnmuteCommand.cs index e59c4334a..043611442 100644 --- a/Plugins/Mute/Commands/UnmuteCommand.cs +++ b/Plugins/Mute/Commands/UnmuteCommand.cs @@ -20,8 +20,8 @@ public UnmuteCommand(CommandConfiguration config, ITranslationLookup translation Permission = EFClient.Permission.Moderator; RequiresTarget = true; SupportedGames = Plugin.SupportedGames; - Arguments = new[] - { + Arguments = + [ new CommandArgument { Name = translationLookup["COMMANDS_ARGS_PLAYER"], @@ -32,7 +32,7 @@ public UnmuteCommand(CommandConfiguration config, ITranslationLookup translation Name = translationLookup["COMMANDS_ARGS_REASON"], Required = true } - }; + ]; } public override async Task ExecuteAsync(GameEvent gameEvent) diff --git a/Plugins/Mute/Mute.csproj b/Plugins/Mute/Mute.csproj index a227b7fed..3341c5258 100644 --- a/Plugins/Mute/Mute.csproj +++ b/Plugins/Mute/Mute.csproj @@ -8,6 +8,7 @@ Library Debug;Release;Prerelease AnyCPU + IW4MAdmin.Plugins.Mute diff --git a/Plugins/Mute/MuteManager.cs b/Plugins/Mute/MuteManager.cs index 537465b12..e758d5eb9 100644 --- a/Plugins/Mute/MuteManager.cs +++ b/Plugins/Mute/MuteManager.cs @@ -10,23 +10,15 @@ namespace IW4MAdmin.Plugins.Mute; -public class MuteManager +public class MuteManager( + ILogger logger, + IDatabaseContextFactory databaseContextFactory, + IMetaServiceV2 metaService, + ITranslationLookup translationLookup) { - private readonly IMetaServiceV2 _metaService; - private readonly ITranslationLookup _translationLookup; - private readonly ILogger _logger; - private readonly IDatabaseContextFactory _databaseContextFactory; + private readonly ILogger _logger = logger; private readonly SemaphoreSlim _onMuteAction = new(1, 1); - public MuteManager(ILogger logger, IDatabaseContextFactory databaseContextFactory, - IMetaServiceV2 metaService, ITranslationLookup translationLookup) - { - _logger = logger; - _databaseContextFactory = databaseContextFactory; - _metaService = metaService; - _translationLookup = translationLookup; - } - public static bool IsExpiredMute(MuteStateMeta muteStateMeta) => muteStateMeta.Expiration is not null && muteStateMeta.Expiration < DateTime.UtcNow; @@ -42,7 +34,7 @@ public async Task GetCurrentMuteState(EFClient client) var muteState = await ReadPersistentDataV1(client); clientMuteMeta = new MuteStateMeta { - Reason = muteState is null ? string.Empty : _translationLookup["PLUGINS_MUTE_MIGRATED"], + Reason = muteState is null ? string.Empty : translationLookup["PLUGINS_MUTE_MIGRATED"], Expiration = muteState switch { null => DateTime.UtcNow, @@ -149,7 +141,7 @@ private async Task CreatePenalty(MuteState muteState, EFClient origin, EFClient private async Task ExpireMutePenalties(EFClient client) { - await using var context = _databaseContextFactory.CreateContext(); + await using var context = databaseContextFactory.CreateContext(); var mutePenalties = await context.Penalties .Where(penalty => penalty.OffenderId == client.ClientId) .Where(penalty => penalty.Type == EFPenalty.PenaltyType.Mute || penalty.Type == EFPenalty.PenaltyType.TempMute) @@ -184,7 +176,7 @@ public static async Task PerformGameCommand(Server server, EFClient? client, Mut } private async Task ReadPersistentDataV1(EFClient client) => TryParse( - (await _metaService.GetPersistentMeta(Plugin.MuteKey, client.ClientId))?.Value, out var muteState) + (await metaService.GetPersistentMeta(Plugin.MuteKey, client.ClientId))?.Value, out var muteState) ? muteState : null; @@ -195,7 +187,7 @@ public static async Task PerformGameCommand(Server server, EFClient? client, Mut if (clientMuteMeta is not null) return clientMuteMeta; // Get meta from database and store in client if exists - clientMuteMeta = await _metaService.GetPersistentMetaValue(Plugin.MuteKey, client.ClientId); + clientMuteMeta = await metaService.GetPersistentMetaValue(Plugin.MuteKey, client.ClientId); if (clientMuteMeta is not null) client.SetAdditionalProperty(Plugin.MuteKey, clientMuteMeta); return clientMuteMeta; @@ -204,6 +196,6 @@ public static async Task PerformGameCommand(Server server, EFClient? client, Mut private async Task WritePersistentData(EFClient client, MuteStateMeta clientMuteMeta) { client.SetAdditionalProperty(Plugin.MuteKey, clientMuteMeta); - await _metaService.SetPersistentMetaValue(Plugin.MuteKey, clientMuteMeta, client.ClientId); + await metaService.SetPersistentMetaValue(Plugin.MuteKey, clientMuteMeta, client.ClientId); } } diff --git a/Plugins/Mute/Plugin.cs b/Plugins/Mute/Plugin.cs index d1c36815a..44ca8b2cd 100644 --- a/Plugins/Mute/Plugin.cs +++ b/Plugins/Mute/Plugin.cs @@ -21,15 +21,14 @@ public class Plugin : IPluginV2 public const string MuteKey = "IW4MMute"; public static IManager Manager { get; private set; } = null!; - public static Server.Game[] SupportedGames { get; private set; } = Array.Empty(); + public static Server.Game[] SupportedGames { get; private set; } = []; private static readonly string[] DisabledCommands = [nameof(PrivateMessageAdminsCommand), "PrivateMessageCommand"]; private readonly IInteractionRegistration _interactionRegistration; private readonly IRemoteCommandService _remoteCommandService; private readonly MuteManager _muteManager; private const string MuteInteraction = "Webfront::Profile::Mute"; - public Plugin(IInteractionRegistration interactionRegistration, - IRemoteCommandService remoteCommandService, MuteManager muteManager) + public Plugin(IInteractionRegistration interactionRegistration, IRemoteCommandService remoteCommandService, MuteManager muteManager) { _interactionRegistration = interactionRegistration; _remoteCommandService = remoteCommandService; @@ -37,7 +36,6 @@ public Plugin(IInteractionRegistration interactionRegistration, IManagementEventSubscriptions.Load += OnLoad; IManagementEventSubscriptions.Unload += OnUnload; - IManagementEventSubscriptions.ClientStateInitialized += OnClientStateInitialized; IGameServerEventSubscriptions.ClientDataUpdated += OnClientDataUpdated; @@ -73,7 +71,7 @@ private Task OnLoad(IManager manager, CancellationToken cancellationToken) return !DisabledCommands.Contains(command.GetType().Name) && !command.IsBroadcast; }); - _interactionRegistration.RegisterInteraction(MuteInteraction, async (targetClientId, game, token) => + _interactionRegistration.RegisterInteraction(MuteInteraction, async (targetClientId, game, _) => { if (!targetClientId.HasValue || game.HasValue && !SupportedGames.Contains((Server.Game)game.Value)) { @@ -81,16 +79,16 @@ private Task OnLoad(IManager manager, CancellationToken cancellationToken) } var clientMuteMetaState = - (await _muteManager.GetCurrentMuteState(new EFClient {ClientId = targetClientId.Value})) + (await _muteManager.GetCurrentMuteState(new EFClient { ClientId = targetClientId.Value })) .MuteState; var server = manager.GetServers().First(); - string GetCommandName(Type commandType) => - manager.Commands.FirstOrDefault(command => command.GetType() == commandType)?.Name ?? ""; - return clientMuteMetaState is MuteState.Unmuted or MuteState.Unmuting ? CreateMuteInteraction(targetClientId.Value, server, GetCommandName) : CreateUnmuteInteraction(targetClientId.Value, server, GetCommandName); + + string GetCommandName(Type commandType) => + manager.Commands.FirstOrDefault(command => command.GetType() == commandType)?.Name ?? string.Empty; }); return Task.CompletedTask; } @@ -109,9 +107,9 @@ private async Task OnClientDataUpdated(ClientDataUpdateEvent updateEvent, Cancel } var networkIds = updateEvent.Clients.Select(client => client.NetworkId).ToList(); - var ingameClients = updateEvent.Server.ConnectedClients.Where(client => networkIds.Contains(client.NetworkId)); + var inGameClients = updateEvent.Server.ConnectedClients.Where(client => networkIds.Contains(client.NetworkId)); - await Task.WhenAll(ingameClients.Select(async client => + await Task.WhenAll(inGameClients.Select(async client => { var muteMetaUpdate = await _muteManager.GetCurrentMuteState(client); if (!muteMetaUpdate.CommandExecuted) @@ -137,7 +135,7 @@ private async Task OnClientMessaged(ClientMessageEvent messageEvent, Cancellatio { var muteMetaSay = await _muteManager.GetCurrentMuteState(messageEvent.Origin); - if (muteMetaSay.MuteState == MuteState.Muted) + if (muteMetaSay.MuteState is MuteState.Muted) { // Let the client know when their mute expires. messageEvent.Origin.Tell(Utilities.CurrentLocalization @@ -160,16 +158,16 @@ private async Task OnClientStateInitialized(ClientStateInitializeEvent state, Ca switch (muteMetaJoin) { - case {MuteState: MuteState.Muted}: + case { MuteState: MuteState.Muted }: // Let the client know when their mute expires. state.Client.Tell(Utilities.CurrentLocalization .LocalizationIndex["PLUGINS_MUTE_REMAINING_TIME"].FormatExt( - muteMetaJoin is {Expiration: not null} + muteMetaJoin is { Expiration: not null } ? muteMetaJoin.Expiration.Value.HumanizeForCurrentCulture() : Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_NEVER"], muteMetaJoin.Reason)); break; - case {MuteState: MuteState.Unmuting}: + case { MuteState: MuteState.Unmuting }: // Handle unmute of unmuted players. await _muteManager.Unmute(state.Client.CurrentServer, Utilities.IW4MAdminClient(), state.Client, muteMetaJoin.Reason ?? string.Empty); @@ -191,6 +189,29 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server, Values = (Dictionary?)null }; + var presetReasonInput = new + { + Name = "PresetReason", + Label = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_ACTION_LABEL_PRESET_REASON"], + Type = "select", + Values = (Dictionary?)new Dictionary + { + { string.Empty, string.Empty }, + { + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_ABUSIVE"], + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_ABUSIVE"] + }, + { + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_SPAMMING"], + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_SPAMMING"] + }, + { + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_OTHER"], + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_OTHER"] + } + } + }; + var durationInput = new { Name = "Duration", @@ -198,16 +219,16 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server, Type = "select", Values = (Dictionary?)new Dictionary { - {"5m", TimeSpan.FromMinutes(5).HumanizeForCurrentCulture()}, - {"30m", TimeSpan.FromMinutes(30).HumanizeForCurrentCulture()}, - {"1h", TimeSpan.FromHours(1).HumanizeForCurrentCulture()}, - {"6h", TimeSpan.FromHours(6).HumanizeForCurrentCulture()}, - {"1d", TimeSpan.FromDays(1).HumanizeForCurrentCulture()}, - {"p", Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_ACTION_SELECTION_PERMANENT"]} + { "5m", TimeSpan.FromMinutes(5).HumanizeForCurrentCulture() }, + { "30m", TimeSpan.FromMinutes(30).HumanizeForCurrentCulture() }, + { "1h", TimeSpan.FromHours(1).HumanizeForCurrentCulture() }, + { "6h", TimeSpan.FromHours(6).HumanizeForCurrentCulture() }, + { "1d", TimeSpan.FromDays(1).HumanizeForCurrentCulture() }, + { "p", Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_ACTION_SELECTION_PERMANENT"] } } }; - var inputs = new[] {reasonInput, durationInput}; + var inputs = new[] { reasonInput, presetReasonInput, durationInput }; var inputsJson = JsonSerializer.Serialize(inputs); return new InteractionData @@ -216,10 +237,10 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server, Name = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MUTE"], DisplayMeta = "oi-volume-off", ActionPath = "DynamicAction", - ActionMeta = new() + ActionMeta = new Dictionary { - {"InteractionId", MuteInteraction}, - {"Inputs", inputsJson}, + { "InteractionId", MuteInteraction }, + { "Inputs", inputsJson }, { "ActionButtonLabel", Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MUTE"] @@ -228,7 +249,7 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server, "Name", Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MUTE"] }, - {"ShouldRefresh", true.ToString()} + { "ShouldRefresh", true.ToString() } }, MinimumPermission = Data.Models.Client.EFClient.Permission.Moderator, Source = Name, @@ -250,11 +271,14 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server, args.Add(duration); } - if (meta.TryGetValue(reasonInput.Name, out var reason)) + var definedReason = meta.TryGetValue(reasonInput.Name, out var reason) ? reason : string.Empty; + if (meta.TryGetValue(presetReasonInput.Name, out var presetReason) && string.IsNullOrWhiteSpace(definedReason)) { - args.Add(reason); + definedReason = presetReason; } + args.Add(definedReason); + var commandResponse = await _remoteCommandService.Execute(originId, targetId, muteCommand, args, server); return string.Join(".", commandResponse.Select(result => result.Response)); @@ -272,21 +296,20 @@ private InteractionData CreateUnmuteInteraction(int targetClientId, Server serve Type = "text", }; - var inputs = new[] {reasonInput}; + var inputs = new[] { reasonInput }; var inputsJson = JsonSerializer.Serialize(inputs); return new InteractionData { EntityId = targetClientId, - Name = Utilities.CurrentLocalization.LocalizationIndex[ - "WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_UNMUTE"], + Name = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_UNMUTE"], DisplayMeta = "oi-volume-high", ActionPath = "DynamicAction", - ActionMeta = new() + ActionMeta = new Dictionary { - {"InteractionId", MuteInteraction}, - {"Outputs", reasonInput.Name}, - {"Inputs", inputsJson}, + { "InteractionId", MuteInteraction }, + { "Outputs", reasonInput.Name }, + { "Inputs", inputsJson }, { "ActionButtonLabel", Utilities.CurrentLocalization.LocalizationIndex[ @@ -297,7 +320,7 @@ private InteractionData CreateUnmuteInteraction(int targetClientId, Server serve Utilities.CurrentLocalization.LocalizationIndex[ "WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_UNMUTE"] }, - {"ShouldRefresh", true.ToString()} + { "ShouldRefresh", true.ToString() } }, MinimumPermission = Data.Models.Client.EFClient.Permission.Moderator, Source = Name,