From f0fd4c66e9b234399372803e7f4b6b59533a56f7 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Thu, 11 Apr 2019 20:43:05 -0500 Subject: [PATCH] add configuration option to force local translations fix silly bug with no being able to claim ownership continue work on configuration via webfront --- Application/Localization/Configure.cs | 21 ++-- SharedLibraryCore/Commands/NativeCommands.cs | 4 +- .../Configuration/ApplicationConfiguration.cs | 66 +++++++++---- .../Helpers/ConfigurationIgnore.cs | 11 +++ .../Helpers/ConfigurationOptional.cs | 11 +++ .../Helpers/LinkedConfiguration.cs | 15 +++ .../Controllers/ConfigurationController.cs | 26 +++++ WebfrontCore/ViewModels/ConfigurationInfo.cs | 19 ++++ WebfrontCore/Views/Configuration/Index.cshtml | 95 ++++++++++++++++++- .../Views/Configuration/_ListItem.cshtml | 6 ++ WebfrontCore/WebfrontCore.csproj | 4 + WebfrontCore/wwwroot/css/bootstrap-custom.css | 2 +- .../wwwroot/css/bootstrap-custom.scss | 2 +- WebfrontCore/wwwroot/js/configuration.js | 17 +++- 14 files changed, 264 insertions(+), 35 deletions(-) create mode 100644 SharedLibraryCore/Helpers/ConfigurationIgnore.cs create mode 100644 SharedLibraryCore/Helpers/ConfigurationOptional.cs create mode 100644 SharedLibraryCore/Helpers/LinkedConfiguration.cs create mode 100644 WebfrontCore/ViewModels/ConfigurationInfo.cs create mode 100644 WebfrontCore/Views/Configuration/_ListItem.cshtml diff --git a/Application/Localization/Configure.cs b/Application/Localization/Configure.cs index bf6a36d81..24eaa259f 100644 --- a/Application/Localization/Configure.cs +++ b/Application/Localization/Configure.cs @@ -17,17 +17,20 @@ namespace IW4MAdmin.Application.Localization string currentLocale = string.IsNullOrEmpty(customLocale) ? CultureInfo.CurrentCulture.Name : customLocale; string[] localizationFiles = Directory.GetFiles(Path.Join(Utilities.OperatingDirectory, "Localization"), $"*.{currentLocale}.json"); - try + if (!Program.ServerManager.GetApplicationSettings()?.Configuration()?.UseLocalTranslations ?? false) { - var api = Endpoint.Get(); - var localization = api.GetLocalization(currentLocale).Result; - Utilities.CurrentLocalization = localization; - return; - } + try + { + var api = Endpoint.Get(); + var localization = api.GetLocalization(currentLocale).Result; + Utilities.CurrentLocalization = localization; + return; + } - catch (Exception) - { - // the online localization failed so will default to local files + catch (Exception) + { + // the online localization failed so will default to local files + } } // culture doesn't exist so we just want language diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index 53e9ebd1a..fb14ad791 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -35,7 +35,7 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { if (await (E.Owner.Manager.GetClientService() as ClientService).GetOwnerCount() == 0 && - !E.Target.SetLevel(EFClient.Permission.Owner, Utilities.IW4MAdminClient(E.Owner)).Failed) + !E.Origin.SetLevel(EFClient.Permission.Owner, Utilities.IW4MAdminClient(E.Owner)).Failed) { E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_OWNER_SUCCESS"]); } @@ -484,7 +484,7 @@ namespace SharedLibraryCore.Commands // we don't really want to tell them if they're demoted haha if (newPerm > oldPerm) { - ActiveClient.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"].FormatExt(newPerm))); + ActiveClient.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"].FormatExt(newPerm)); } } diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 60a1390bc..36820d559 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -1,64 +1,92 @@ -using SharedLibraryCore.Interfaces; +using SharedLibraryCore.Helpers; +using SharedLibraryCore.Interfaces; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; namespace SharedLibraryCore.Configuration { public class ApplicationConfiguration : IBaseConfiguration { [LocalizedDisplayName("SETUP_ENABLE_WEBFRONT")] + [LinkedConfiguration("WebfrontBindUrl", "ManualWebfrontUrl")] 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; } + [LocalizedDisplayName("SETUP_ENABLE_MULTIOWN")] public bool EnableMultipleOwners { get; set; } [LocalizedDisplayName("SETUP_ENABLE_STEPPEDPRIV")] public bool EnableSteppedHierarchy { get; set; } - [LocalizedDisplayName("SETUP_DISPLAY_SOCIAL")] - public bool EnableSocialLink { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_USE_LOCAL_TRANSLATIONS")] + public bool UseLocalTranslations { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_IGNORE_BOTS")] + public bool IgnoreBots { get; set; } + + [LinkedConfiguration("CustomSayName")] [LocalizedDisplayName("SETUP_ENABLE_CUSTOMSAY")] public bool EnableCustomSayName { get; set; } [LocalizedDisplayName("SETUP_SAY_NAME")] public string CustomSayName { get; set; } + + [LocalizedDisplayName("SETUP_DISPLAY_SOCIAL")] + [LinkedConfiguration("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("WEBFRONT_CONFIGURATION_BIND_URL")] - public string WebfrontBindUrl { get; set; } - [LocalizedDisplayName("WEBFRONT_CONFIGURATION_MANUAL_URL")] - public string ManualWebfrontUrl { get; set; } - public string WebfrontUrl => string.IsNullOrEmpty(ManualWebfrontUrl) ? WebfrontBindUrl?.Replace("0.0.0.0", "127.0.0.1") : ManualWebfrontUrl; + [LocalizedDisplayName("SETUP_USE_CUSTOMENCODING")] + [LinkedConfiguration("CustomParserEncoding")] public bool EnableCustomParserEncoding { get; set; } [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENCODING")] public string CustomParserEncoding { get; set; } + + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENABLE_WHITELIST")] + [LinkedConfiguration("WebfrontConnectionWhitelist")] + public bool EnableWebfrontConnectionWhitelist { get; set; } + public List WebfrontConnectionWhitelist { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_CUSTOM_LOCALE")] + [LinkedConfiguration("CustomLocale")] public bool EnableCustomLocale { get; set; } [LocalizedDisplayName("WEBFRONT_CONFIGURATION_CUSTOM_LOCALE")] public string CustomLocale { get; set; } + + [ConfigurationOptional] [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_IGNORE_BOTS")] - public bool IgnoreBots { get; set; } [LocalizedDisplayName("WEBFRONT_CONFIGURATION_MAX_TB")] public TimeSpan MaximumTempBanTime { get; set; } = new TimeSpan(24 * 30, 0, 0); - [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENABLE_WHITELIST")] - public bool EnableWebfrontConnectionWhitelist { get; set; } - public List WebfrontConnectionWhitelist { get; set; } - [LocalizedDisplayName("WEBFRONT_CONFIGURATION_USE_LOCAL_TRANSLATIONS")] - public bool UseLocalTranslations { get; set; } - public string Id { get; set; } - public List Servers { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_AUTOMESSAGE_PERIOD")] public int AutoMessagePeriod { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_AUTOMESSAGES")] public List AutoMessages { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_GLOBAL_RULES")] public List GlobalRules { get; set; } - public List Maps { get; set; } - public List QuickMessages { get; set; } + [LocalizedDisplayName("WEBFRONT_CONFIGURATION_DISALLOWED_NAMES")] public List DisallowedClientNames { get; set; } + public List Servers { get; set; } + + + [ConfigurationIgnore] + public string Id { get; set; } + [ConfigurationIgnore] + public List Maps { get; set; } + [ConfigurationIgnore] + public List QuickMessages { get; set; } + [ConfigurationIgnore] + public string WebfrontUrl => string.IsNullOrEmpty(ManualWebfrontUrl) ? WebfrontBindUrl?.Replace("0.0.0.0", "127.0.0.1") : ManualWebfrontUrl; public IBaseConfiguration Generate() { diff --git a/SharedLibraryCore/Helpers/ConfigurationIgnore.cs b/SharedLibraryCore/Helpers/ConfigurationIgnore.cs new file mode 100644 index 000000000..6fcb4f083 --- /dev/null +++ b/SharedLibraryCore/Helpers/ConfigurationIgnore.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SharedLibraryCore.Helpers +{ + [AttributeUsage(AttributeTargets.Property, Inherited = false)] + public class ConfigurationIgnore : Attribute + { + } +} diff --git a/SharedLibraryCore/Helpers/ConfigurationOptional.cs b/SharedLibraryCore/Helpers/ConfigurationOptional.cs new file mode 100644 index 000000000..1d41eb2e6 --- /dev/null +++ b/SharedLibraryCore/Helpers/ConfigurationOptional.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SharedLibraryCore.Helpers +{ + [AttributeUsage(AttributeTargets.Property, Inherited = false)] + public class ConfigurationOptional : Attribute + { + } +} diff --git a/SharedLibraryCore/Helpers/LinkedConfiguration.cs b/SharedLibraryCore/Helpers/LinkedConfiguration.cs new file mode 100644 index 000000000..640d8c463 --- /dev/null +++ b/SharedLibraryCore/Helpers/LinkedConfiguration.cs @@ -0,0 +1,15 @@ +using System; + +namespace SharedLibraryCore.Helpers +{ + [AttributeUsage(AttributeTargets.Property, Inherited = false)] + public class LinkedConfiguration : Attribute + { + public string[] LinkedPropertyNames { get; set; } + + public LinkedConfiguration(params string[] linkedPropertyNames) + { + LinkedPropertyNames = linkedPropertyNames; + } + } +} diff --git a/WebfrontCore/Controllers/ConfigurationController.cs b/WebfrontCore/Controllers/ConfigurationController.cs index 444a67e79..0a4dec0a3 100644 --- a/WebfrontCore/Controllers/ConfigurationController.cs +++ b/WebfrontCore/Controllers/ConfigurationController.cs @@ -1,8 +1,12 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using SharedLibraryCore.Configuration; +using WebfrontCore.ViewModels; namespace WebfrontCore.Controllers { @@ -12,5 +16,27 @@ namespace WebfrontCore.Controllers { return View("Index", Manager.GetApplicationSettings().Configuration()); } + + [HttpPost] + public IActionResult Edit(ApplicationConfiguration config) + { + return View("Index", Manager.GetApplicationSettings().Configuration()); + } + + public IActionResult GetNewListItem(string propertyName, int itemCount) + { + var config = Manager.GetApplicationSettings().Configuration(); + var propertyInfo = config.GetType().GetProperties().First(_prop => _prop.Name == propertyName); + + var configInfo = new ConfigurationInfo() + { + Configuration = config, + PropertyValue = (IList)propertyInfo.GetValue(config), + PropertyInfo = propertyInfo, + NewItemCount = itemCount + }; + + return PartialView("_ListItem", configInfo); + } } } \ No newline at end of file diff --git a/WebfrontCore/ViewModels/ConfigurationInfo.cs b/WebfrontCore/ViewModels/ConfigurationInfo.cs new file mode 100644 index 000000000..50b6c6947 --- /dev/null +++ b/WebfrontCore/ViewModels/ConfigurationInfo.cs @@ -0,0 +1,19 @@ +using SharedLibraryCore.Interfaces; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace WebfrontCore.ViewModels +{ + public class ConfigurationInfo + { + public string PropertyName => PropertyInfo.Name; + public PropertyInfo PropertyInfo { get; set; } + public IList PropertyValue { get; set; } + public IBaseConfiguration Configuration { get; set; } + public int NewItemCount { get; set; } + } +} diff --git a/WebfrontCore/Views/Configuration/Index.cshtml b/WebfrontCore/Views/Configuration/Index.cshtml index 2c053f3ed..01a5f75bb 100644 --- a/WebfrontCore/Views/Configuration/Index.cshtml +++ b/WebfrontCore/Views/Configuration/Index.cshtml @@ -5,10 +5,101 @@ string optionalText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["COMMAND_HELP_OPTIONAL"]; string advancedText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_ADVANCED"]; string addText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_ADD"]; + + var properties = Model.GetType().GetProperties(); + + string[] getLinkedPropertyName(System.Reflection.PropertyInfo info) + { + var test = (info.GetCustomAttributes(false) + .Where(_attr => _attr.GetType() == typeof(SharedLibraryCore.Helpers.LinkedConfiguration)) + .FirstOrDefault() as SharedLibraryCore.Helpers.LinkedConfiguration); + + return test?.LinkedPropertyNames ?? new string[0]; + } + + bool shouldIgnore(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false) + .Where(_attr => _attr.GetType() == typeof(SharedLibraryCore.Helpers.ConfigurationIgnore)) + .FirstOrDefault() as SharedLibraryCore.Helpers.ConfigurationIgnore) != null; + + bool isOptional(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false) + .Where(_attr => _attr.GetType() == typeof(SharedLibraryCore.Helpers.ConfigurationOptional)) + .FirstOrDefault() as SharedLibraryCore.Helpers.ConfigurationOptional) != null; + + bool hasLinkedParent(System.Reflection.PropertyInfo info) + { + return Model.GetType().GetProperties().SelectMany(_prop => getLinkedPropertyName(_prop)).Contains(info.Name); + } }
-
+
+
+
+ + @foreach (var property in properties) + { + if (shouldIgnore(property)) + { + continue; + } + + string[] linkedPropertyNames = getLinkedPropertyName(property); + + if (property.PropertyType.Name == typeof(System.Boolean).Name) + { + + + + var attributes = linkedPropertyNames.Length > 0 ? new { htmlAttributes = new { @class = "has-related-content", data_related_content = string.Join(',', linkedPropertyNames.Select(_id => $"#{_id}_content")) } } : null; +
+ @Html.Editor(property.Name, attributes) + @Html.Label(property.Name, null, new { @class = "form-check-label ml-1" }) +
+ } + + else if (property.PropertyType.Name.Contains("List")) + { + if (hasLinkedParent(property)) + { +
+ @if (linkedPropertyNames.Length == 0) + { + @Html.Label(property.Name, null, new { @class = "pt-3" }) + } + @Html.Editor(property.Name, new { htmlAttributes = new { @class = $"form-group form-control bg-dark text-white-50 {(linkedPropertyNames.Length == 0 ? "mb-3" : "mb-0")}" } }) +
+ } + + else + { + @Html.Label(property.Name, null, new { @class = "bg-primary pl-3 pr-3 p-2 mb-0 mt-0 w-100" }) +
+ @Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-control bg-dark text-white-50 mt-2", placeholder = isOptional(property) ? optionalText : "" } }) + @addText +
+ } + } + + else + { + if (hasLinkedParent(property)) + { +
+ @Html.Label(property.Name, null, new { @class = "pt-3" }) + @Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : "" } }) +
+ } + + else + { + + } + } + } + +
+
+
@@ -80,7 +171,7 @@
diff --git a/WebfrontCore/Views/Configuration/_ListItem.cshtml b/WebfrontCore/Views/Configuration/_ListItem.cshtml new file mode 100644 index 000000000..9b1d1a819 --- /dev/null +++ b/WebfrontCore/Views/Configuration/_ListItem.cshtml @@ -0,0 +1,6 @@ +@model WebfrontCore.ViewModels.ConfigurationInfo +@{ + int index = Model.PropertyValue.Count + (Model.NewItemCount - Model.PropertyValue.Count); +} + + \ No newline at end of file diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj index 376374215..053ec4119 100644 --- a/WebfrontCore/WebfrontCore.csproj +++ b/WebfrontCore/WebfrontCore.csproj @@ -93,5 +93,9 @@ + + + + diff --git a/WebfrontCore/wwwroot/css/bootstrap-custom.css b/WebfrontCore/wwwroot/css/bootstrap-custom.css index 59470f44d..8d302e39d 100644 --- a/WebfrontCore/wwwroot/css/bootstrap-custom.css +++ b/WebfrontCore/wwwroot/css/bootstrap-custom.css @@ -6465,7 +6465,7 @@ form *, select { margin-top: -0.5rem !important; } /* Configuration */ -.configuration-form input[type='text'], .configuration-form input[type='number'] { +.configuration-form input[type='text'], .configuration-form input[type='number'], input.text-box { border: 1px solid #fd7e14; } .hide { diff --git a/WebfrontCore/wwwroot/css/bootstrap-custom.scss b/WebfrontCore/wwwroot/css/bootstrap-custom.scss index e78ce8026..c8da1aef9 100644 --- a/WebfrontCore/wwwroot/css/bootstrap-custom.scss +++ b/WebfrontCore/wwwroot/css/bootstrap-custom.scss @@ -282,7 +282,7 @@ form *, select { } /* Configuration */ -.configuration-form input[type='text'], .configuration-form input[type='number'] { +.configuration-form input[type='text'], .configuration-form input[type='number'], input.text-box { border: 1px solid $orange; } diff --git a/WebfrontCore/wwwroot/js/configuration.js b/WebfrontCore/wwwroot/js/configuration.js index 4a9593187..2400c0f0b 100644 --- a/WebfrontCore/wwwroot/js/configuration.js +++ b/WebfrontCore/wwwroot/js/configuration.js @@ -1,7 +1,7 @@ $(document).ready(function() { $.each($('.has-related-content'), function (key, value) { value = $(value); - if (value.attr('checked').length > 0) { + if (value.attr('checked') !== undefined && value.attr('checked').length > 0) { $(value.data('related-content')).slideDown(); } }); @@ -10,4 +10,19 @@ var isChecked = $(this).is(':checked'); isChecked ? $($(this).data('related-content')).slideDown() : $($(this).data('related-content')).slideUp(); }); + + $('.configuration-add-new').click(function (e) { + e.preventDefault(); + //let totalItems = $(this).siblings().length; + //let inputHtml = $(this).siblings().last().get(0).outerHTML; + //inputHtml = inputHtml.replace('_' + totalItems - 1 + '_', '_' + totalItems + '_'); + //inputHtml = inputHtml.replace('[' + totalItems - 1 + ']', '[' + totalItems + ']'); + //$(this).parent().prepend(inputHtml); + + let parentElement = $(this).parent(); + + $.get($(this).attr('href') + '&itemCount=' + $(this).siblings().length, function (response) { + parentElement.prepend(response); + }); + }); }); \ No newline at end of file