diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 134eb677c..999ddccea 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -1,6 +1,7 @@ using SharedLibraryCore.Configuration.Attributes; using SharedLibraryCore.Interfaces; using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace SharedLibraryCore.Configuration @@ -8,63 +9,79 @@ namespace SharedLibraryCore.Configuration public class ApplicationConfiguration : IBaseConfiguration { [LocalizedDisplayName("SETUP_ENABLE_WEBFRONT")] - [ConfigurationLinked("WebfrontBindUrl", "ManualWebfrontUrl", "WebfrontPrimaryColor", "WebfrontSecondaryColor", "WebfrontCustomBranding")] + [ConfigurationLinked("WebfrontBindUrl", "ManualWebfrontUrl", "WebfrontPrimaryColor", "WebfrontSecondaryColor", + "WebfrontCustomBranding")] public bool EnableWebFront { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_BIND_URL")] public string WebfrontBindUrl { get; set; } + [ConfigurationOptional] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_MANUAL_URL")] public string ManualWebfrontUrl { get; set; } + [ConfigurationOptional] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_PRIMARY_COLOR")] public string WebfrontPrimaryColor { get; set; } + [ConfigurationOptional] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_SECONDARY_COLOR")] public string WebfrontSecondaryColor { get; set; } + [ConfigurationOptional] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_CUSTOM_BRANDING")] public string WebfrontCustomBranding { get; set; } [LocalizedDisplayName("SETUP_ENABLE_MULTIOWN")] public bool EnableMultipleOwners { get; set; } + [LocalizedDisplayName("SETUP_ENABLE_STEPPEDPRIV")] public bool EnableSteppedHierarchy { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_USE_LOCAL_TRANSLATIONS")] public bool UseLocalTranslations { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_IGNORE_BOTS")] public bool IgnoreBots { get; set; } [ConfigurationLinked("CustomSayName")] [LocalizedDisplayName("SETUP_ENABLE_CUSTOMSAY")] public bool EnableCustomSayName { get; set; } + [LocalizedDisplayName("SETUP_SAY_NAME")] public string CustomSayName { get; set; } [LocalizedDisplayName("SETUP_DISPLAY_SOCIAL")] [ConfigurationLinked("SocialLinkAddress", "SocialLinkTitle")] public bool EnableSocialLink { get; set; } + [LocalizedDisplayName("SETUP_SOCIAL_LINK")] public string SocialLinkAddress { get; set; } + [LocalizedDisplayName("SETUP_SOCIAL_TITLE")] public string SocialLinkTitle { get; set; } + [LocalizedDisplayName("SETUP_CONTACT_URI")] public string ContactUri { get; set; } [LocalizedDisplayName("SETUP_USE_CUSTOMENCODING")] [ConfigurationLinked("CustomParserEncoding")] public bool EnableCustomParserEncoding { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENCODING")] public string CustomParserEncoding { get; set; } [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENABLE_WHITELIST")] [ConfigurationLinked("WebfrontConnectionWhitelist")] public bool EnableWebfrontConnectionWhitelist { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_WHITELIST_LIST")] public string[] WebfrontConnectionWhitelist { get; set; } = new string[0]; [LocalizedDisplayName("WEBFRONT_CONFIGURATION_CUSTOM_LOCALE")] [ConfigurationLinked("CustomLocale")] public bool EnableCustomLocale { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_CUSTOM_LOCALE")] public string CustomLocale { get; set; } @@ -76,42 +93,63 @@ namespace SharedLibraryCore.Configuration [LocalizedDisplayName("WEBFRONT_CONFIGURATION_DB_PROVIDER")] public string DatabaseProvider { get; set; } = "sqlite"; + [ConfigurationOptional] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_CONNECTION_STRING")] public string ConnectionString { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_RCON_POLLRATE")] public int RConPollRate { get; set; } = 5000; + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_MAX_TB")] public TimeSpan MaximumTempBanTime { get; set; } = new TimeSpan(24 * 30, 0, 0); + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENABLE_COLOR_CODES")] public bool EnableColorCodes { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_AUTOMESSAGE_PERIOD")] public int AutoMessagePeriod { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_AUTOMESSAGES")] public string[] AutoMessages { get; set; } = new string[0]; + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_GLOBAL_RULES")] public string[] GlobalRules { get; set; } = new string[0]; + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_DISALLOWED_NAMES")] public string[] DisallowedClientNames { get; set; } = new string[0]; + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_MAP_CHANGE_DELAY")] public int MapChangeDelaySeconds { get; set; } = 5; - [UIHint("ServerConfiguration")] + + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_BAN_DURATIONS")] + public TimeSpan[] BanDurations { get; set; } = { + TimeSpan.FromHours(1), + TimeSpan.FromHours(6), + TimeSpan.FromDays(1), + TimeSpan.FromDays(2), + TimeSpan.FromDays(7), + TimeSpan.FromDays(31) + }; + + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_PRESET_BAN_REASONS")] + public Dictionary PresetPenaltyReasons { get; set; } = new Dictionary + {{"afk", "Away from keyboard"}, {"ci", "Connection interrupted. Reconnect"}}; + [UIHint("ServerConfiguration")] public ServerConfiguration[] Servers { get; set; } + [ConfigurationIgnore] public string Id { get; set; } + [ConfigurationIgnore] public string SubscriptionId { get; set; } + [ConfigurationIgnore] public MapConfiguration[] Maps { get; set; } + [ConfigurationIgnore] public QuickMessageConfiguration[] QuickMessages { get; set; } + [ConfigurationIgnore] - public string Id { get; set; } - [ConfigurationIgnore] - public string SubscriptionId { get; set; } - [ConfigurationIgnore] - public MapConfiguration[] Maps { get; set; } - [ConfigurationIgnore] - public QuickMessageConfiguration[] QuickMessages { get; set; } - [ConfigurationIgnore] - public string WebfrontUrl => string.IsNullOrEmpty(ManualWebfrontUrl) ? WebfrontBindUrl?.Replace("0.0.0.0", "127.0.0.1") : ManualWebfrontUrl; - [ConfigurationIgnore] - public bool IgnoreServerConnectionLost { get; set; } - [ConfigurationIgnore] - public Uri MasterUrl { get; set; } = new Uri("http://api.raidmax.org:5000"); + public string WebfrontUrl => string.IsNullOrEmpty(ManualWebfrontUrl) + ? WebfrontBindUrl?.Replace("0.0.0.0", "127.0.0.1") + : ManualWebfrontUrl; + + [ConfigurationIgnore] public bool IgnoreServerConnectionLost { get; set; } + [ConfigurationIgnore] public Uri MasterUrl { get; set; } = new Uri("http://api.raidmax.org:5000"); public IBaseConfiguration Generate() { diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index ac8a91a61..ab30705e6 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -1003,6 +1003,12 @@ namespace SharedLibraryCore public static string FindRuleForReason(this string reason, ApplicationConfiguration appConfig, Server server) { + // allow for penalty presets + if (appConfig.PresetPenaltyReasons?.ContainsKey(reason.ToLower()) ?? false) + { + return appConfig.PresetPenaltyReasons[reason.ToLower()]; + } + var regex = Regex.Match(reason, @"(rule|serverrule)(\d+)", RegexOptions.IgnoreCase); if (!regex.Success) { diff --git a/WebfrontCore/Controllers/ActionController.cs b/WebfrontCore/Controllers/ActionController.cs index a6e1caaa6..aadd4f313 100644 --- a/WebfrontCore/Controllers/ActionController.cs +++ b/WebfrontCore/Controllers/ActionController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -25,9 +26,10 @@ namespace WebfrontCore.Controllers private readonly string _unflagCommandName; private readonly string _setLevelCommandName; - public ActionController(IManager manager, IEnumerable registeredCommands) : base(manager) + public ActionController(IManager manager, IEnumerable registeredCommands, + ApplicationConfiguration appConfig) : base(manager) { - _appConfig = manager.GetApplicationSettings().Configuration(); + _appConfig = appConfig; foreach (var cmd in registeredCommands) { @@ -73,23 +75,33 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name = "Reason", - Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], + Name = "Reason", + Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], }, new InputInfo() { - Name ="Duration", - Label=Localization["WEBFRONT_ACTION_LABEL_DURATION"], - Type="select", - Values = new Dictionary() - { - {"1", $"1 {Localization["GLOBAL_TIME_HOUR"]}" }, - {"2", $"6 {Localization["GLOBAL_TIME_HOURS"]}" }, - {"3", $"1 {Localization["GLOBAL_TIME_DAY"]}" }, - {"4", $"2 {Localization["GLOBAL_TIME_DAYS"]}" }, - {"5", $"1 {Localization["GLOBAL_TIME_WEEK"]}" }, - {"6", $"{Localization["WEBFRONT_ACTION_SELECTION_PERMANENT"]}" }, - } + Name = "PresetReason", + Type = "select", + Label = Localization["WEBFRONT_ACTION_LABEL_PRESET_REASON"], + Values = GetPresetPenaltyReasons() + }, + new InputInfo() + { + Name = "Duration", + Label = Localization["WEBFRONT_ACTION_LABEL_DURATION"], + Type = "select", + Values = _appConfig.BanDurations + .Select((item, index) => new + { + Id = (index + 1).ToString(), + Value = item.HumanizeForCurrentCulture() + } + ) + .Append(new + { + Id = (_appConfig.BanDurations.Length + 1).ToString(), + Value = Localization["WEBFRONT_ACTION_SELECTION_PERMANENT"] + }).ToDictionary(duration => duration.Id, duration => duration.Value), } }, Action = "BanAsync", @@ -99,34 +111,24 @@ namespace WebfrontCore.Controllers return View("_ActionForm", info); } - public async Task BanAsync(int targetId, string Reason, int Duration) + public async Task BanAsync(int targetId, string reason, int duration, string presetReason = null) { - string duration = string.Empty; - - var loc = Utilities.CurrentLocalization.LocalizationIndex; - - switch (Duration) + var fallthroughReason = presetReason ?? reason; + string command; + // permanent + if (duration > _appConfig.BanDurations.Length) { - case 1: - duration = $"1{loc["GLOBAL_TIME_HOURS"][0]}"; - break; - case 2: - duration = $"6{loc["GLOBAL_TIME_HOURS"][0]}"; - break; - case 3: - duration = $"1{loc["GLOBAL_TIME_DAYS"][0]}"; - break; - case 4: - duration = $"2{loc["GLOBAL_TIME_DAYS"][0]}"; - break; - case 5: - duration = $"1{loc["GLOBAL_TIME_WEEKS"][0]}"; - break; + command = $"{_appConfig.CommandPrefix}{_banCommandName} @{targetId} {fallthroughReason}"; + } + // temporary ban + else + { + var durationSpan = _appConfig.BanDurations[duration - 1]; + var durationValue = durationSpan.TotalHours.ToString(CultureInfo.InvariantCulture) + + Localization["GLOBAL_TIME_HOURS"][0]; + command = + $"{_appConfig.CommandPrefix}{_tempbanCommandName} @{targetId} {durationValue} {fallthroughReason}"; } - - string command = Duration == 6 ? - $"{_appConfig.CommandPrefix}{_banCommandName} @{targetId} {Reason}" : - $"{_appConfig.CommandPrefix}{_tempbanCommandName} @{targetId} {duration} {Reason}"; var server = Manager.GetServers().First(); @@ -147,8 +149,8 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name = "Reason", - Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], + Name = "Reason", + Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], } }, Action = "UnbanAsync", @@ -197,7 +199,7 @@ namespace WebfrontCore.Controllers public async Task LoginAsync(int clientId, string password) { - return await Task.FromResult(RedirectToAction("LoginAsync", "Account", new { clientId, password })); + return await Task.FromResult(RedirectToAction("LoginAsync", "Account", new {clientId, password})); } public IActionResult EditForm() @@ -210,14 +212,14 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name ="level", - Label=Localization["WEBFRONT_PROFILE_LEVEL"], - Type="select", + Name = "level", + Label = Localization["WEBFRONT_PROFILE_LEVEL"], + Type = "select", Values = Enum.GetValues(typeof(Permission)).OfType() .Where(p => p <= Client.Level) .Where(p => p != Permission.Banned) .Where(p => p != Permission.Flagged) - .ToDictionary(p => p.ToString(), p=> p.ToLocalizedLevelName()) + .ToDictionary(p => p.ToString(), p => p.ToLocalizedLevelName()) }, }, Action = "EditAsync", @@ -255,7 +257,10 @@ namespace WebfrontCore.Controllers public string GenerateLoginTokenAsync() { var state = Manager.TokenAuthenticator.GenerateNextToken(Client.NetworkId); - return string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_SUCCESS"], state.Token, $"{state.RemainingTime} {Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_MINUTES"]}", Client.ClientId); + return string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_SUCCESS"], + state.Token, + $"{state.RemainingTime} {Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_MINUTES"]}", + Client.ClientId); } public IActionResult ChatForm(long id) @@ -321,9 +326,16 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name = "reason", - Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], - } + Name = "reason", + Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], + }, + new InputInfo() + { + Name = "PresetReason", + Type = "select", + Label = Localization["WEBFRONT_ACTION_LABEL_PRESET_REASON"], + Values = GetPresetPenaltyReasons() + }, }, Action = "FlagAsync", ShouldRefresh = true @@ -332,14 +344,14 @@ namespace WebfrontCore.Controllers return View("_ActionForm", info); } - public async Task FlagAsync(int targetId, string reason) + public async Task FlagAsync(int targetId, string reason, string presetReason = null) { var server = Manager.GetServers().First(); return await Task.FromResult(RedirectToAction("ExecuteAsync", "Console", new { serverId = server.EndPoint, - command = $"{_appConfig.CommandPrefix}{_flagCommandName} @{targetId} {reason}" + command = $"{_appConfig.CommandPrefix}{_flagCommandName} @{targetId} {presetReason ?? reason}" })); } @@ -353,8 +365,8 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name = "reason", - Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], + Name = "reason", + Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], } }, Action = "UnflagAsync", @@ -385,8 +397,15 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name = "reason", - Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], + Name = "reason", + Label = Localization["WEBFRONT_ACTION_LABEL_REASON"], + }, + new InputInfo() + { + Name = "PresetReason", + Type = "select", + Label = Localization["WEBFRONT_ACTION_LABEL_PRESET_REASON"], + Values = GetPresetPenaltyReasons() }, new InputInfo() { @@ -402,7 +421,7 @@ namespace WebfrontCore.Controllers return View("_ActionForm", info); } - public async Task KickAsync(int targetId, string reason) + public async Task KickAsync(int targetId, string reason, string presetReason = null) { var client = Manager.GetActiveClients().FirstOrDefault(_client => _client.ClientId == targetId); @@ -414,8 +433,23 @@ namespace WebfrontCore.Controllers return await Task.FromResult(RedirectToAction("ExecuteAsync", "Console", new { serverId = client.CurrentServer.EndPoint, - command = $"{_appConfig.CommandPrefix}{_kickCommandName} {client.ClientNumber} {reason}" + command = $"{_appConfig.CommandPrefix}{_kickCommandName} {client.ClientNumber} {presetReason ?? reason}" })); } + + private Dictionary GetPresetPenaltyReasons() => _appConfig.PresetPenaltyReasons.Values + .Concat(_appConfig.GlobalRules) + .Concat(_appConfig.Servers.SelectMany(server => server.Rules)) + .Distinct() + .Select((value, index) => new + { + Value = value + }) + // this is used for the default empty optional value + .Prepend(new + { + Value = "" + }) + .ToDictionary(item => item.Value, item => item.Value); } -} +} \ No newline at end of file