diff --git a/Application/ApplicationManager.cs b/Application/ApplicationManager.cs index cb07eb714..9d9d10404 100644 --- a/Application/ApplicationManager.cs +++ b/Application/ApplicationManager.cs @@ -9,7 +9,6 @@ using SharedLibraryCore.Configuration.Validation; using SharedLibraryCore.Database; using SharedLibraryCore.Database.Models; using SharedLibraryCore.Dtos; -using SharedLibraryCore.Events; using SharedLibraryCore.Exceptions; using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; @@ -49,7 +48,7 @@ namespace IW4MAdmin.Application private readonly ClientService ClientSvc; readonly AliasService AliasSvc; readonly PenaltyService PenaltySvc; - public BaseConfigurationHandler ConfigHandler; + public IConfigurationHandler ConfigHandler; GameEventHandler Handler; readonly IPageList PageList; private readonly Dictionary _loggers = new Dictionary(); @@ -58,9 +57,12 @@ namespace IW4MAdmin.Application private readonly CancellationTokenSource _tokenSource; private readonly Dictionary> _operationLookup = new Dictionary>(); private readonly ITranslationLookup _translationLookup; - private readonly CommandConfiguration _commandConfiguration; + private readonly IConfigurationHandler _commandConfiguration; + private readonly IPluginImporter _pluginImporter; - public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable commands, ITranslationLookup translationLookup, CommandConfiguration commandConfiguration) + public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable commands, + ITranslationLookup translationLookup, IConfigurationHandler commandConfiguration, + IConfigurationHandler appConfigHandler, IPluginImporter pluginImporter) { MiddlewareActionHandler = actionHandler; _servers = new ConcurrentBag(); @@ -68,7 +70,7 @@ namespace IW4MAdmin.Application ClientSvc = new ClientService(); AliasSvc = new AliasService(); PenaltySvc = new PenaltyService(); - ConfigHandler = new BaseConfigurationHandler("IW4MAdminSettings"); + ConfigHandler = appConfigHandler; StartTime = DateTime.UtcNow; PageList = new PageList(); AdditionalEventParsers = new List(); @@ -80,6 +82,7 @@ namespace IW4MAdmin.Application _commands = commands.ToList(); _translationLookup = translationLookup; _commandConfiguration = commandConfiguration; + _pluginImporter = pluginImporter; } public async Task ExecuteEvent(GameEvent newEvent) @@ -157,9 +160,9 @@ namespace IW4MAdmin.Application return Servers; } - public IList GetCommands() + public IList GetCommands() { - return new List(); + return _commands; } public async Task UpdateServerStates() @@ -246,18 +249,21 @@ namespace IW4MAdmin.Application ExternalIPAddress = await Utilities.GetExternalIP(); #region PLUGINS - SharedLibraryCore.Plugins.PluginImporter.Load(this); - - foreach (var Plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins) + foreach (var plugin in _pluginImporter.ActivePlugins) { try { - await Plugin.OnLoadAsync(this); + if (plugin is ScriptPlugin scriptPlugin) + { + await scriptPlugin.Initialize(this); + } + + await plugin.OnLoadAsync(this); } catch (Exception ex) { - Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_PLUGIN"]} {Plugin.Name}"); + Logger.WriteError($"{_translationLookup["SERVER_ERROR_PLUGIN"]} {plugin.Name}"); Logger.WriteDebug(ex.GetExceptionInfo()); } } @@ -298,7 +304,7 @@ namespace IW4MAdmin.Application } newConfig.Servers = newConfig.Servers.Append((ServerConfiguration)serverConfig.Generate()).ToArray(); - } while (Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["SETUP_SERVER_SAVE"])); + } while (Utilities.PromptBool(_translationLookup["SETUP_SERVER_SAVE"])); config = newConfig; await ConfigHandler.Save(); @@ -324,9 +330,10 @@ namespace IW4MAdmin.Application if (!validationResult.IsValid) { - throw new ConfigurationException(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_CONFIGURATION_ERROR"]) + throw new ConfigurationException("MANAGER_CONFIGURATION_ERROR") { - Errors = validationResult.Errors.Select(_error => _error.ErrorMessage).ToArray() + Errors = validationResult.Errors.Select(_error => _error.ErrorMessage).ToArray(), + ConfigurationFileName = ConfigHandler.FileName }; } @@ -376,31 +383,34 @@ namespace IW4MAdmin.Application _commands.RemoveAll(_cmd => _cmd.GetType() == typeof(OwnerCommand)); } - foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands) + List commandsToAddToConfig = new List(); + var cmdConfig = _commandConfiguration.Configuration(); + + if (cmdConfig == null) { - _commands.Add(C); + cmdConfig = new CommandConfiguration(); + commandsToAddToConfig.AddRange(_commands); } - if (_commandConfiguration == null) + else { - // todo: this is here for now. it's not the most elegant but currently there's no way to know all the plugin comamnds during DI - var handler = new BaseConfigurationHandler("CommandConfiguration"); - var cmdConfig = new CommandConfiguration(); + var unsavedCommands = _commands.Where(_cmd => !cmdConfig.Commands.Keys.Contains(_cmd.GetType().Name)); + commandsToAddToConfig.AddRange(unsavedCommands); + } - foreach (var cmd in _commands) + foreach (var cmd in commandsToAddToConfig) + { + cmdConfig.Commands.Add(cmd.GetType().Name, + new CommandProperties() { - cmdConfig.Commands.Add(cmd.GetType().Name, - new CommandProperties() - { - Name = cmd.Name, - Alias = cmd.Alias, - MinimumPermission = cmd.Permission - }); - } - - handler.Set(cmdConfig); - await handler.Save(); + Name = cmd.Name, + Alias = cmd.Alias, + MinimumPermission = cmd.Permission + }); } + + _commandConfiguration.Set(cmdConfig); + await _commandConfiguration.Save(); #endregion #region META @@ -541,7 +551,7 @@ namespace IW4MAdmin.Application try { - var ServerInstance = new IW4MServer(this, Conf, _translationLookup); + var ServerInstance = new IW4MServer(this, Conf, _translationLookup, _pluginImporter); await ServerInstance.Initialize(); _servers.Add(ServerInstance); @@ -735,7 +745,7 @@ namespace IW4MAdmin.Application public IList GetPluginAssemblies() { - return SharedLibraryCore.Plugins.PluginImporter.PluginAssemblies.Union(SharedLibraryCore.Plugins.PluginImporter.Assemblies).ToList(); + return _pluginImporter.PluginAssemblies.Union(_pluginImporter.Assemblies).ToList(); } public IPageList GetPageList() diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index 93a1d44f4..0f2f3f285 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -27,12 +27,14 @@ namespace IW4MAdmin private GameLogEventDetection LogEvent; private readonly ITranslationLookup _translationLookup; private const int REPORT_FLAG_COUNT = 4; + private readonly IPluginImporter _pluginImporter; public int Id { get; private set; } - public IW4MServer(IManager mgr, ServerConfiguration cfg, ITranslationLookup lookup) : base(mgr, cfg) + public IW4MServer(IManager mgr, ServerConfiguration cfg, ITranslationLookup lookup, IPluginImporter pluginImporter) : base(mgr, cfg) { _translationLookup = lookup; + _pluginImporter = pluginImporter; } override public async Task OnClientConnected(EFClient clientFromLog) @@ -150,7 +152,7 @@ namespace IW4MAdmin } } - foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins) + foreach (var plugin in _pluginImporter.ActivePlugins) { try { @@ -668,7 +670,7 @@ namespace IW4MAdmin await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token); } - foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins) + foreach (var plugin in _pluginImporter.ActivePlugins) { await plugin.OnUnloadAsync(); } diff --git a/Application/Main.cs b/Application/Main.cs index 58a47aca7..9eea2d7d8 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -1,4 +1,5 @@ -using IW4MAdmin.Application.Migration; +using IW4MAdmin.Application.Helpers; +using IW4MAdmin.Application.Migration; using IW4MAdmin.Application.Misc; using Microsoft.Extensions.DependencyInjection; using SharedLibraryCore; @@ -20,6 +21,7 @@ namespace IW4MAdmin.Application public static ApplicationManager ServerManager; private static Task ApplicationTask; private static readonly BuildNumber _fallbackVersion = BuildNumber.Parse("99.99.99.99"); + private static ServiceProvider serviceProvider; /// /// entrypoint of the application @@ -62,31 +64,49 @@ namespace IW4MAdmin.Application private static async Task LaunchAsync() { restart: + ITranslationLookup translationLookup = null; try { var services = ConfigureServices(); using (var builder = services.BuildServiceProvider()) { - ServerManager = (ApplicationManager)builder.GetRequiredService(); + translationLookup = builder.GetRequiredService(); + var importer = builder.GetRequiredService(); + importer.Load(); + + foreach (var type in importer.CommandTypes) + { + services.AddTransient(typeof(IManagerCommand), type); + } + + foreach (var commandDefinition in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes() + .Where(_command => _command.BaseType == typeof(Command))) + { + services.AddTransient(typeof(IManagerCommand), commandDefinition); + } } + serviceProvider = services.BuildServiceProvider(); + var pluginImporter = serviceProvider.GetRequiredService(); + pluginImporter.Load(); + + ServerManager = (ApplicationManager)serviceProvider.GetRequiredService(); + // do any needed housekeeping file/folder migrations ConfigurationMigration.MoveConfigFolder10518(null); ConfigurationMigration.CheckDirectories(); ServerManager.Logger.WriteInfo(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_VERSION"].FormatExt(Version)); - - await CheckVersion(); + await CheckVersion(translationLookup); await ServerManager.Init(); } catch (Exception e) { - var loc = Utilities.CurrentLocalization.LocalizationIndex; - string failMessage = loc == null ? "Failed to initalize IW4MAdmin" : loc["MANAGER_INIT_FAIL"]; - string exitMessage = loc == null ? "Press any key to exit..." : loc["MANAGER_EXIT"]; + string failMessage = translationLookup == null ? "Failed to initalize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"]; + string exitMessage = translationLookup == null ? "Press any key to exit..." : translationLookup["MANAGER_EXIT"]; Console.WriteLine(failMessage); @@ -95,16 +115,21 @@ namespace IW4MAdmin.Application e = e.InnerException; } - Console.WriteLine(e.Message); - - if (e is ConfigurationException cfgE) + if (e is ConfigurationException configException) { - foreach (string error in cfgE.Errors) + Console.WriteLine(translationLookup[configException.Message].FormatExt(configException.ConfigurationFileName)); + + foreach (string error in configException.Errors) { Console.WriteLine(error); } } + else + { + Console.WriteLine(e.Message); + } + Console.WriteLine(exitMessage); Console.ReadKey(); return; @@ -122,6 +147,8 @@ namespace IW4MAdmin.Application { goto restart; } + + serviceProvider.Dispose(); } /// @@ -131,7 +158,7 @@ namespace IW4MAdmin.Application private static async Task RunApplicationTasksAsync() { var webfrontTask = ServerManager.GetApplicationSettings().Configuration().EnableWebFront ? - WebfrontCore.Program.Init(ServerManager, ServerManager.CancellationToken) : + WebfrontCore.Program.Init(ServerManager, serviceProvider, ServerManager.CancellationToken) : Task.CompletedTask; // we want to run this one on a manual thread instead of letting the thread pool handle it, @@ -155,10 +182,10 @@ namespace IW4MAdmin.Application /// notifies user if an update is available /// /// - private static async Task CheckVersion() + private static async Task CheckVersion(ITranslationLookup translationLookup) { var api = API.Master.Endpoint.Get(); - var loc = Utilities.CurrentLocalization.LocalizationIndex; + var loc = translationLookup; var version = new API.Master.VersionInfo() { @@ -258,22 +285,20 @@ namespace IW4MAdmin.Application { var serviceProvider = new ServiceCollection(); serviceProvider.AddSingleton() - .AddSingleton(_serviceProvider => new BaseConfigurationHandler("IW4MAdminSettings").Configuration()) - .AddSingleton(_serviceProvider => new BaseConfigurationHandler("CommandConfiguration").Configuration()) + .AddSingleton(new BaseConfigurationHandler("IW4MAdminSettings") as IConfigurationHandler) + .AddSingleton(new BaseConfigurationHandler("CommandConfiguration") as IConfigurationHandler) + .AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService>().Configuration()) + .AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService>().Configuration()) .AddSingleton(_serviceProvider => new Logger("IW4MAdmin-Manager")) + .AddSingleton() .AddSingleton() .AddSingleton(_serviceProvider => { - var config = _serviceProvider.GetRequiredService(); - return Localization.Configure.Initialize(config?.UseLocalTranslations ?? false, config?.EnableCustomLocale ?? false ? (config.CustomLocale ?? "en-US") : "en-US"); + var config = _serviceProvider.GetRequiredService>().Configuration(); + return Localization.Configure.Initialize(useLocalTranslation: config?.UseLocalTranslations ?? false, + customLocale: config?.EnableCustomLocale ?? false ? (config.CustomLocale ?? "en-US") : "en-US"); }); - - foreach (var commandDefinition in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes().Where(_command => _command.BaseType == typeof(Command))) - { - serviceProvider.AddTransient(typeof(IManagerCommand), commandDefinition); - } - return serviceProvider; } } diff --git a/SharedLibraryCore/PluginImporter.cs b/Application/Misc/PluginImporter.cs similarity index 57% rename from SharedLibraryCore/PluginImporter.cs rename to Application/Misc/PluginImporter.cs index 8b898d766..3231ad7d9 100644 --- a/SharedLibraryCore/PluginImporter.cs +++ b/Application/Misc/PluginImporter.cs @@ -4,17 +4,30 @@ using System.Collections.Generic; using System.Reflection; using SharedLibraryCore.Interfaces; using System.Linq; +using SharedLibraryCore; -namespace SharedLibraryCore.Plugins +namespace IW4MAdmin.Application.Helpers { - public class PluginImporter + public class PluginImporter : IPluginImporter { - public static List ActiveCommands = new List(); - public static List ActivePlugins = new List(); - public static List PluginAssemblies = new List(); - public static List Assemblies = new List(); + public IList CommandTypes { get; private set; } = new List(); + public IList ActivePlugins { get; private set; } = new List(); + public IList PluginAssemblies { get; private set; } = new List(); + public IList Assemblies { get; private set; } = new List(); - public static bool Load(IManager Manager) + private readonly ILogger _logger; + private readonly ITranslationLookup _translationLookup; + + public PluginImporter(ILogger logger, ITranslationLookup translationLookup) + { + _logger = logger; + _translationLookup = translationLookup; + } + + /// + /// Loads all the assembly and javascript plugins + /// + public void Load() { string pluginDir = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}"; string[] dllFileNames = null; @@ -35,16 +48,15 @@ namespace SharedLibraryCore.Plugins if (dllFileNames.Length == 0 && scriptFileNames.Length == 0) { - Manager.GetLogger(0).WriteDebug(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_NOTFOUND"]); - return true; + _logger.WriteDebug(_translationLookup["PLUGIN_IMPORTER_NOTFOUND"]); + return; } // load up the script plugins foreach (string fileName in scriptFileNames) { var plugin = new ScriptPlugin(fileName); - plugin.Initialize(Manager).Wait(); - Manager.GetLogger(0).WriteDebug($"Loaded script plugin \"{ plugin.Name }\" [{plugin.Version}]"); + _logger.WriteDebug($"Loaded script plugin \"{ plugin.Name }\" [{plugin.Version}]"); ActivePlugins.Add(plugin); } @@ -63,12 +75,10 @@ namespace SharedLibraryCore.Plugins Type[] types = Plugin.GetTypes(); foreach (Type assemblyType in types) { - if (assemblyType.IsClass && assemblyType.BaseType.Name == "Command") + if (assemblyType.IsClass && assemblyType.BaseType == typeof(Command)) { - Object commandObject = Activator.CreateInstance(assemblyType); - Command newCommand = (Command)commandObject; - ActiveCommands.Add(newCommand); - Manager.GetLogger(0).WriteDebug($"{Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_REGISTERCMD"]} \"{newCommand.Name}\""); + CommandTypes.Add(assemblyType); + _logger.WriteDebug($"{_translationLookup["PLUGIN_IMPORTER_REGISTERCMD"]} \"{assemblyType.Name}\""); LoadedCommands++; continue; } @@ -78,26 +88,26 @@ namespace SharedLibraryCore.Plugins if (assemblyType.GetInterface("IPlugin", false) == null) continue; - Object notifyObject = Activator.CreateInstance(assemblyType); + var notifyObject = Activator.CreateInstance(assemblyType); IPlugin newNotify = (IPlugin)notifyObject; - if (ActivePlugins.Find(x => x.Name == newNotify.Name) == null) + if (ActivePlugins.FirstOrDefault(x => x.Name == newNotify.Name) == null) { ActivePlugins.Add(newNotify); PluginAssemblies.Add(Plugin); - Manager.GetLogger(0).WriteDebug($"Loaded plugin \"{ newNotify.Name }\" [{newNotify.Version}]"); + _logger.WriteDebug($"Loaded plugin \"{newNotify.Name}\" [{newNotify.Version}]"); } } catch (Exception e) { - Manager.GetLogger(0).WriteWarning(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_ERROR"].FormatExt(Plugin.Location)); - Manager.GetLogger(0).WriteDebug(e.GetExceptionInfo()); + _logger.WriteWarning(_translationLookup["PLUGIN_IMPORTER_ERROR"].FormatExt(Plugin.Location)); + _logger.WriteDebug(e.GetExceptionInfo()); } } } } - Manager.GetLogger(0).WriteInfo($"Loaded {ActivePlugins.Count} plugins and registered {LoadedCommands} commands."); - return true; + + _logger.WriteInfo($"Loaded {ActivePlugins.Count} plugins and registered {LoadedCommands} plugin commands."); } } } diff --git a/Plugins/AutomessageFeed/AutomessageFeed.csproj b/Plugins/AutomessageFeed/AutomessageFeed.csproj index 58e8e9437..a4c2f5c6c 100644 --- a/Plugins/AutomessageFeed/AutomessageFeed.csproj +++ b/Plugins/AutomessageFeed/AutomessageFeed.csproj @@ -10,7 +10,7 @@ - + diff --git a/Plugins/IW4ScriptCommands/Commands/KillPlayerCommand.cs b/Plugins/IW4ScriptCommands/Commands/KillPlayerCommand.cs index d8fe0ebe7..bef7d7d7a 100644 --- a/Plugins/IW4ScriptCommands/Commands/KillPlayerCommand.cs +++ b/Plugins/IW4ScriptCommands/Commands/KillPlayerCommand.cs @@ -1,5 +1,8 @@ using SharedLibraryCore; +using SharedLibraryCore.Commands; +using SharedLibraryCore.Configuration; using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Interfaces; using System.Threading.Tasks; namespace IW4ScriptCommands.Commands @@ -9,15 +12,22 @@ namespace IW4ScriptCommands.Commands /// public class KillPlayerCommand : Command { - public KillPlayerCommand() : base("killplayer", "kill a player", "kp", EFClient.Permission.Administrator, true, new[] + public KillPlayerCommand(CommandConfiguration config, ITranslationLookup lookup) : base(config, lookup) { - new CommandArgument() + Name = "killplayer"; + Description = "kill a player"; + Alias = "kp"; + Permission = EFClient.Permission.Administrator; + RequiresTarget = true; + Arguments = new[] { - Name = "player", - Required = true - } - }) - { } + new CommandArgument() + { + Name = "player", + Required = true + } + }; + } public override async Task ExecuteAsync(GameEvent E) { diff --git a/Plugins/IW4ScriptCommands/GscApiController.cs b/Plugins/IW4ScriptCommands/GscApiController.cs index 2642b68cb..9a846f83c 100644 --- a/Plugins/IW4ScriptCommands/GscApiController.cs +++ b/Plugins/IW4ScriptCommands/GscApiController.cs @@ -23,7 +23,7 @@ namespace WebfrontCore.Controllers.API public IActionResult ClientInfo(string networkId) { var clientInfo = Manager.GetActiveClients() - .FirstOrDefault(c => c.NetworkId == networkId.ConvertGuidToLong()); + .FirstOrDefault(c => c.NetworkId == networkId.ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber)); if (clientInfo != null) { diff --git a/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj b/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj index 5597b8497..bde75dc1b 100644 --- a/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj +++ b/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj @@ -10,7 +10,7 @@ - + diff --git a/Plugins/LiveRadar/LiveRadar.csproj b/Plugins/LiveRadar/LiveRadar.csproj index 2bf620294..bec099675 100644 --- a/Plugins/LiveRadar/LiveRadar.csproj +++ b/Plugins/LiveRadar/LiveRadar.csproj @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Login/Commands/CLogin.cs b/Plugins/Login/Commands/CLogin.cs deleted file mode 100644 index a805228d8..000000000 --- a/Plugins/Login/Commands/CLogin.cs +++ /dev/null @@ -1,39 +0,0 @@ -using SharedLibraryCore; -using SharedLibraryCore.Database.Models; -using System.Threading.Tasks; - -namespace IW4MAdmin.Plugins.Login.Commands -{ - public class CLogin : Command - { - public CLogin() : base("login", Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_DESC"], "li", EFClient.Permission.Trusted, false, new CommandArgument[] - { - new CommandArgument() - { - Name = Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ARGS_PASSWORD"], - Required = true - } - }) - { } - - public override async Task ExecuteAsync(GameEvent E) - { - bool success = E.Owner.Manager.TokenAuthenticator.AuthorizeToken(E.Origin.NetworkId, E.Data); - - if (!success) - { - string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(E.Data, E.Origin.PasswordSalt)); - success = hashedPassword[0] == E.Origin.Password; - } - - if (success) - { - Plugin.AuthorizedClients[E.Origin.ClientId] = true; - } - - _ = success ? - E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]) : - E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL"]); - } - } -} diff --git a/Plugins/Login/Commands/LoginCommand.cs b/Plugins/Login/Commands/LoginCommand.cs new file mode 100644 index 000000000..debe4be20 --- /dev/null +++ b/Plugins/Login/Commands/LoginCommand.cs @@ -0,0 +1,49 @@ +using SharedLibraryCore; +using SharedLibraryCore.Commands; +using SharedLibraryCore.Configuration; +using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Interfaces; +using System.Threading.Tasks; + +namespace IW4MAdmin.Plugins.Login.Commands +{ + public class LoginCommand : Command + { + public LoginCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup) + { + Name = "login"; + Description = _translationLookup["PLUGINS_LOGIN_COMMANDS_LOGIN_DESC"]; + Alias = "li"; + Permission = EFClient.Permission.Trusted; + RequiresTarget = false; + Arguments = new CommandArgument[] + { + new CommandArgument() + { + Name = Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ARGS_PASSWORD"], + Required = true + } + }; + } + + public override async Task ExecuteAsync(GameEvent E) + { + bool success = E.Owner.Manager.TokenAuthenticator.AuthorizeToken(E.Origin.NetworkId, E.Data); + + if (!success) + { + string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(E.Data, E.Origin.PasswordSalt)); + success = hashedPassword[0] == E.Origin.Password; + } + + if (success) + { + Plugin.AuthorizedClients[E.Origin.ClientId] = true; + } + + _ = success ? + E.Origin.Tell(_translationLookup["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]) : + E.Origin.Tell(_translationLookup["PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL"]); + } + } +} diff --git a/Plugins/Login/Login.csproj b/Plugins/Login/Login.csproj index da15e2ed5..ed3444425 100644 --- a/Plugins/Login/Login.csproj +++ b/Plugins/Login/Login.csproj @@ -23,7 +23,7 @@ - + diff --git a/Plugins/Login/Plugin.cs b/Plugins/Login/Plugin.cs index 91fe6c360..b18c00aee 100644 --- a/Plugins/Login/Plugin.cs +++ b/Plugins/Login/Plugin.cs @@ -1,6 +1,7 @@ using System.Collections.Concurrent; using System.Reflection; using System.Threading.Tasks; +using IW4MAdmin.Plugins.Login.Commands; using SharedLibraryCore; using SharedLibraryCore.Commands; using SharedLibraryCore.Configuration; @@ -43,11 +44,11 @@ namespace IW4MAdmin.Plugins.Login E.Origin.Level == EFClient.Permission.Console) return Task.CompletedTask; - if (((Command)E.Extra).Name == new CSetPassword().Name && + if (E.Extra.GetType() == typeof(SetPasswordCommand) && E.Origin?.Password == null) return Task.CompletedTask; - if (((Command)E.Extra).Name == new Commands.CLogin().Name) + if (E.Extra.GetType() == typeof(LoginCommand)) return Task.CompletedTask; if (E.Extra.GetType() == typeof(RequestTokenCommand)) diff --git a/Plugins/ProfanityDeterment/ProfanityDeterment.csproj b/Plugins/ProfanityDeterment/ProfanityDeterment.csproj index 50e7aabab..b6d2e8ec1 100644 --- a/Plugins/ProfanityDeterment/ProfanityDeterment.csproj +++ b/Plugins/ProfanityDeterment/ProfanityDeterment.csproj @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Stats/Commands/MostPlayed.cs b/Plugins/Stats/Commands/MostPlayedCommand.cs similarity index 74% rename from Plugins/Stats/Commands/MostPlayed.cs rename to Plugins/Stats/Commands/MostPlayedCommand.cs index 605a259b8..45ba38055 100644 --- a/Plugins/Stats/Commands/MostPlayed.cs +++ b/Plugins/Stats/Commands/MostPlayedCommand.cs @@ -9,12 +9,14 @@ using SharedLibraryCore.Database; using System.Collections.Generic; using SharedLibraryCore.Database.Models; using IW4MAdmin.Plugins.Stats.Helpers; +using SharedLibraryCore.Configuration; +using SharedLibraryCore.Interfaces; namespace IW4MAdmin.Plugins.Stats.Commands { - class MostPlayed : Command + class MostPlayedCommand : Command { - public static async Task> GetMostPlayed(Server s) + public static async Task> GetMostPlayed(Server s, ITranslationLookup translationLookup) { long serverId = StatManager.GetIdForServer(s); @@ -50,18 +52,25 @@ namespace IW4MAdmin.Plugins.Stats.Commands var iqList = await iqStats.ToListAsync(); mostPlayed.AddRange(iqList.Select(stats => - $"^3{stats.Name}^7 - ^5{stats.Kills} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KILLS"]} | ^5{Utilities.GetTimePassed(DateTime.UtcNow.AddSeconds(-stats.TotalConnectionTime), false)} ^7{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_PLAYER"].ToLower()}")); + $"^3{stats.Name}^7 - ^5{stats.Kills} ^7{translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{Utilities.GetTimePassed(DateTime.UtcNow.AddSeconds(-stats.TotalConnectionTime), false)} ^7{translationLookup["WEBFRONT_PROFILE_PLAYER"].ToLower()}")); } return mostPlayed; } - public MostPlayed() : base("mostplayed", Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_MOSTPLAYED_DESC"], "mp", EFClient.Permission.User, false) { } + public MostPlayedCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup) + { + Name = "mostplayed"; + Description = translationLookup["PLUGINS_STATS_COMMANDS_MOSTPLAYED_DESC"]; + Alias = "mp"; + Permission = EFClient.Permission.User; + RequiresTarget = false; + } public override async Task ExecuteAsync(GameEvent E) { - var topStats = await GetMostPlayed(E.Owner); + var topStats = await GetMostPlayed(E.Owner, _translationLookup); if (!E.Message.IsBroadcastCommand()) { foreach (var stat in topStats) diff --git a/Plugins/Stats/Commands/ResetStats.cs b/Plugins/Stats/Commands/ResetStats.cs index 1e426cd2b..a07d2bc3c 100644 --- a/Plugins/Stats/Commands/ResetStats.cs +++ b/Plugins/Stats/Commands/ResetStats.cs @@ -1,8 +1,10 @@ using IW4MAdmin.Plugins.Stats.Models; using Microsoft.EntityFrameworkCore; using SharedLibraryCore; +using SharedLibraryCore.Configuration; using SharedLibraryCore.Database; using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Interfaces; using System.Linq; using System.Threading.Tasks; @@ -10,7 +12,14 @@ namespace IW4MAdmin.Plugins.Stats.Commands { public class ResetStats : Command { - public ResetStats() : base("resetstats", Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_RESET_DESC"], "rs", EFClient.Permission.User, false) { } + public ResetStats(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup) + { + Name = "resetstats"; + Description = translationLookup["PLUGINS_STATS_COMMANDS_RESET_DESC"]; + Alias = "rs"; + Permission = EFClient.Permission.User; + RequiresTarget = false; + } public override async Task ExecuteAsync(GameEvent E) { @@ -41,12 +50,12 @@ namespace IW4MAdmin.Plugins.Stats.Commands // fixme: this doesn't work properly when another context exists await ctx.SaveChangesAsync(); } - E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]); + E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]); } else { - E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_RESET_FAIL"]); + E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_FAIL"]); } } } diff --git a/Plugins/Stats/Commands/TopStats.cs b/Plugins/Stats/Commands/TopStats.cs index c0185f72f..15afe293a 100644 --- a/Plugins/Stats/Commands/TopStats.cs +++ b/Plugins/Stats/Commands/TopStats.cs @@ -9,17 +9,19 @@ using SharedLibraryCore.Database; using System.Collections.Generic; using SharedLibraryCore.Database.Models; using IW4MAdmin.Plugins.Stats.Helpers; +using SharedLibraryCore.Configuration; +using SharedLibraryCore.Interfaces; namespace IW4MAdmin.Plugins.Stats.Commands { class TopStats : Command { - public static async Task> GetTopStats(Server s) + public static async Task> GetTopStats(Server s, ITranslationLookup translationLookup) { long serverId = StatManager.GetIdForServer(s); - List topStatsText = new List() + var topStatsText = new List() { - $"^5--{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_TOP_TEXT"]}--" + $"^5--{translationLookup["PLUGINS_STATS_COMMANDS_TOP_TEXT"]}--" }; using (var db = new DatabaseContext(true)) @@ -46,7 +48,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands .Take(5); var statsList = (await iqStats.ToListAsync()) - .Select(stats => $"^3{stats.Name}^7 - ^5{stats.KDR} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"]} | ^5{stats.Performance} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"]}"); + .Select(stats => $"^3{stats.Name}^7 - ^5{stats.KDR} ^7{translationLookup["PLUGINS_STATS_TEXT_KDR"]} | ^5{stats.Performance} ^7{translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"]}"); topStatsText.AddRange(statsList); } @@ -56,18 +58,25 @@ namespace IW4MAdmin.Plugins.Stats.Commands { topStatsText = new List() { - Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_NOQUALIFY"] + translationLookup["PLUGINS_STATS_TEXT_NOQUALIFY"] }; } return topStatsText; } - public TopStats() : base("topstats", Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_TOP_DESC"], "ts", EFClient.Permission.User, false) { } + public TopStats(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup) + { + Name = "topstats"; + Description = translationLookup["PLUGINS_STATS_COMMANDS_TOP_DESC"]; + Alias = "ts"; + Permission = EFClient.Permission.User; + RequiresTarget = false; + } public override async Task ExecuteAsync(GameEvent E) { - var topStats = await GetTopStats(E.Owner); + var topStats = await GetTopStats(E.Owner, _translationLookup); if (!E.Message.IsBroadcastCommand()) { foreach (var stat in topStats) diff --git a/Plugins/Stats/Commands/ViewStats.cs b/Plugins/Stats/Commands/ViewStats.cs index d6b9813a3..bfe18a682 100644 --- a/Plugins/Stats/Commands/ViewStats.cs +++ b/Plugins/Stats/Commands/ViewStats.cs @@ -1,35 +1,40 @@ using SharedLibraryCore; -using SharedLibraryCore.Services; using IW4MAdmin.Plugins.Stats.Models; -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using SharedLibraryCore.Database; using Microsoft.EntityFrameworkCore; using IW4MAdmin.Plugins.Stats.Helpers; using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Configuration; +using SharedLibraryCore.Interfaces; +using SharedLibraryCore.Commands; namespace IW4MAdmin.Plugins.Stats.Commands { - public class CViewStats : Command + public class ViewStatsCommand : Command { - public CViewStats() : base("stats", Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_VIEW_DESC"], "xlrstats", EFClient.Permission.User, false, new CommandArgument[] + public ViewStatsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup) + { + + Name = "stats"; + Description = translationLookup["PLUGINS_STATS_COMMANDS_VIEW_DESC"]; + Alias = "xlrstats"; + Permission = EFClient.Permission.User; + RequiresTarget = false; + Arguments = new CommandArgument[] { new CommandArgument() { Name = "player", Required = false } - }) - { } + }; + } public override async Task ExecuteAsync(GameEvent E) { - var loc = Utilities.CurrentLocalization.LocalizationIndex; - - String statLine; + string statLine; EFClientStatistics pStats; if (E.Data.Length > 0 && E.Target == null) @@ -38,7 +43,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands if (E.Target == null) { - E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_FAIL"]); + E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_FAIL"]); } } @@ -48,7 +53,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands if (E.Target != null) { int performanceRanking = await StatManager.GetClientOverallRanking(E.Target.ClientId); - string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}"; + string performanceRankingString = performanceRanking == 0 ? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}"; if (E.Owner.GetClientsAsList().Any(_client => _client.Equals(E.Target))) { @@ -62,13 +67,13 @@ namespace IW4MAdmin.Plugins.Stats.Commands pStats = (await ctx.Set().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId)); } } - statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}"; + statLine = $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}"; } else { int performanceRanking = await StatManager.GetClientOverallRanking(E.Origin.ClientId); - string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}"; + string performanceRankingString = performanceRanking == 0 ? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}"; if (E.Owner.GetClientsAsList().Any(_client => _client.Equals(E.Origin))) { @@ -82,13 +87,13 @@ namespace IW4MAdmin.Plugins.Stats.Commands pStats = (await ctx.Set().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId)); } } - statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}"; + statLine = $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}"; } if (E.Message.IsBroadcastCommand()) { string name = E.Target == null ? E.Origin.Name : E.Target.Name; - E.Owner.Broadcast(loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(name)); + E.Owner.Broadcast(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(name)); E.Owner.Broadcast(statLine); } @@ -96,7 +101,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands { if (E.Target != null) { - E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(E.Target.Name)); + E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(E.Target.Name)); } E.Origin.Tell(statLine); diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index bfb8de4b6..9bd06281f 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -477,12 +477,14 @@ namespace IW4MAdmin.Plugins.Stats async Task topStats(Server s) { - return string.Join(Environment.NewLine, await Commands.TopStats.GetTopStats(s)); + // todo: this needs to needs to be updated when we DI the lookup + return string.Join(Environment.NewLine, await Commands.TopStats.GetTopStats(s, Utilities.CurrentLocalization.LocalizationIndex)); } async Task mostPlayed(Server s) { - return string.Join(Environment.NewLine, await Commands.MostPlayed.GetMostPlayed(s)); + // todo: this needs to needs to be updated when we DI the lookup + return string.Join(Environment.NewLine, await Commands.MostPlayedCommand.GetMostPlayed(s, Utilities.CurrentLocalization.LocalizationIndex)); } manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills)); diff --git a/Plugins/Stats/Stats.csproj b/Plugins/Stats/Stats.csproj index 5684a8f6d..945e92591 100644 --- a/Plugins/Stats/Stats.csproj +++ b/Plugins/Stats/Stats.csproj @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Tests/ManagerTests.cs b/Plugins/Tests/ManagerTests.cs index 807f38602..96e75652b 100644 --- a/Plugins/Tests/ManagerTests.cs +++ b/Plugins/Tests/ManagerTests.cs @@ -53,7 +53,7 @@ namespace Tests foreach (var command in Manager.GetCommands().OrderByDescending(c => c.Permission).ThenBy(c => c.Name)) { - sb.AppendLine($"|{command.Name}|{command.Alias}|{command.Description}|{command.RequiresTarget}|{command.Syntax.Substring(8).EscapeMarkdown()}|{command.Permission}|"); + sb.AppendLine($"|{command.Name}|{command.Alias}|{command.Description}|{((Command)command).RequiresTarget}|{((Command)command).Syntax.Substring(8).EscapeMarkdown()}|{command.Permission}|"); } Assert.True(false, sb.ToString()); diff --git a/Plugins/Web/StatsWeb/StatsWeb.csproj b/Plugins/Web/StatsWeb/StatsWeb.csproj index c0bb83423..3f1b2cf33 100644 --- a/Plugins/Web/StatsWeb/StatsWeb.csproj +++ b/Plugins/Web/StatsWeb/StatsWeb.csproj @@ -14,7 +14,7 @@ Always - + diff --git a/Plugins/Welcome/Welcome.csproj b/Plugins/Welcome/Welcome.csproj index 1464736ce..3d8c9545f 100644 --- a/Plugins/Welcome/Welcome.csproj +++ b/Plugins/Welcome/Welcome.csproj @@ -16,7 +16,7 @@ - + diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index 056f17fa7..2cf2d7176 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -1317,19 +1317,21 @@ namespace SharedLibraryCore.Commands /// public class ListPluginsCommand : Command { - public ListPluginsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup) + private readonly IPluginImporter _pluginImporter; + public ListPluginsCommand(CommandConfiguration config, ITranslationLookup translationLookup, IPluginImporter pluginImporter) : base(config, translationLookup) { Name = "plugins"; Description = _translationLookup["COMMANDS_PLUGINS_DESC"]; Alias = "p"; Permission = Permission.Administrator; RequiresTarget = false; + _pluginImporter = pluginImporter; } public override Task ExecuteAsync(GameEvent E) { E.Origin.Tell(_translationLookup["COMMANDS_PLUGINS_LOADED"]); - foreach (var P in Plugins.PluginImporter.ActivePlugins) + foreach (var P in _pluginImporter.ActivePlugins) { E.Origin.Tell(string.Format("^3{0} ^7[v^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author)); } diff --git a/SharedLibraryCore/Exceptions/ConfigurationException.cs b/SharedLibraryCore/Exceptions/ConfigurationException.cs index 009f52403..f0d33f955 100644 --- a/SharedLibraryCore/Exceptions/ConfigurationException.cs +++ b/SharedLibraryCore/Exceptions/ConfigurationException.cs @@ -5,6 +5,7 @@ namespace SharedLibraryCore.Exceptions public class ConfigurationException : Exception { public string[] Errors { get; set; } + public string ConfigurationFileName { get; set; } public ConfigurationException(string message) : base(message) { } } diff --git a/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs b/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs index 2fbff5699..38737c2b1 100644 --- a/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs +++ b/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs @@ -9,20 +9,21 @@ namespace SharedLibraryCore.Configuration { public class BaseConfigurationHandler : IConfigurationHandler where T : IBaseConfiguration { - readonly string _configurationPath; T _configuration; public BaseConfigurationHandler(string fn) { - _configurationPath = Path.Join(Utilities.OperatingDirectory, "Configuration", $"{fn}.json"); + FileName = Path.Join(Utilities.OperatingDirectory, "Configuration", $"{fn}.json"); Build(); } + public string FileName { get; } + public void Build() { try { - var configContent = File.ReadAllText(_configurationPath); + var configContent = File.ReadAllText(FileName); _configuration = JsonConvert.DeserializeObject(configContent); } @@ -35,15 +36,22 @@ namespace SharedLibraryCore.Configuration { throw new ConfigurationException("MANAGER_CONFIGURATION_ERROR") { - Errors = new[] { e.Message } + Errors = new[] { e.Message }, + ConfigurationFileName = FileName }; } } public Task Save() { - var appConfigJSON = JsonConvert.SerializeObject(_configuration, Formatting.Indented); - return File.WriteAllTextAsync(_configurationPath, appConfigJSON); + var settings = new JsonSerializerSettings() + { + Formatting = Formatting.Indented + }; + settings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); + + var appConfigJSON = JsonConvert.SerializeObject(_configuration, settings); + return File.WriteAllTextAsync(FileName, appConfigJSON); } public T Configuration() diff --git a/SharedLibraryCore/Interfaces/IConfigurationHandler.cs b/SharedLibraryCore/Interfaces/IConfigurationHandler.cs index 299c952cc..38c1b0111 100644 --- a/SharedLibraryCore/Interfaces/IConfigurationHandler.cs +++ b/SharedLibraryCore/Interfaces/IConfigurationHandler.cs @@ -12,5 +12,6 @@ namespace SharedLibraryCore.Interfaces void Build(); T Configuration(); void Set(T config); + string FileName { get; } } } diff --git a/SharedLibraryCore/Interfaces/IManager.cs b/SharedLibraryCore/Interfaces/IManager.cs index b970a0905..135dfe7ce 100644 --- a/SharedLibraryCore/Interfaces/IManager.cs +++ b/SharedLibraryCore/Interfaces/IManager.cs @@ -17,7 +17,7 @@ namespace SharedLibraryCore.Interfaces void Restart(); ILogger GetLogger(long serverId); IList GetServers(); - IList GetCommands(); + IList GetCommands(); IList GetMessageTokens(); IList GetActiveClients(); IConfigurationHandler GetApplicationSettings(); diff --git a/SharedLibraryCore/Interfaces/IManagerCommand.cs b/SharedLibraryCore/Interfaces/IManagerCommand.cs index cdf920c14..7ab87395c 100644 --- a/SharedLibraryCore/Interfaces/IManagerCommand.cs +++ b/SharedLibraryCore/Interfaces/IManagerCommand.cs @@ -34,5 +34,15 @@ namespace SharedLibraryCore.Interfaces /// Minimum permission required to execute the command /// Permission Permission { get; } + + /// + /// Syntax for using the command + /// + string Syntax { get; } + + /// + /// Indicates if target is required + /// + bool RequiresTarget { get; } } } diff --git a/SharedLibraryCore/Interfaces/IPluginImporter.cs b/SharedLibraryCore/Interfaces/IPluginImporter.cs new file mode 100644 index 000000000..0e7d45adc --- /dev/null +++ b/SharedLibraryCore/Interfaces/IPluginImporter.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace SharedLibraryCore.Interfaces +{ + /// + /// Defines the capabilities of the plugin importer + /// + public interface IPluginImporter + { + /// + /// Command types that are defined in plugin assemblies + /// + IList CommandTypes { get; } + + /// + /// The loaded plugins from plugin assemblies + /// + IList ActivePlugins { get; } + + /// + /// Assemblies that contain plugins + /// + IList PluginAssemblies { get; } + + /// + /// All assemblies in the plugin folder + /// + IList Assemblies { get; } + + /// + /// Loads in plugin assemblies and script plugins + /// + void Load(); + } +} diff --git a/SharedLibraryCore/PartialEntities/EFClient.cs b/SharedLibraryCore/PartialEntities/EFClient.cs index 0e58cf133..545951ff8 100644 --- a/SharedLibraryCore/PartialEntities/EFClient.cs +++ b/SharedLibraryCore/PartialEntities/EFClient.cs @@ -1,8 +1,10 @@ -using SharedLibraryCore.Localization; +using Newtonsoft.Json.Converters; +using SharedLibraryCore.Localization; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; diff --git a/SharedLibraryCore/ScriptPlugin.cs b/SharedLibraryCore/ScriptPlugin.cs index 5428b43b9..f7279b696 100644 --- a/SharedLibraryCore/ScriptPlugin.cs +++ b/SharedLibraryCore/ScriptPlugin.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; namespace SharedLibraryCore { - class ScriptPlugin : IPlugin + public class ScriptPlugin : IPlugin { public string Name { get; set; } diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index c1bc09f6b..bd1c3e42c 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -6,7 +6,7 @@ RaidMax.IW4MAdmin.SharedLibraryCore - 2.2.5 + 2.2.6 RaidMax Forever None Debug;Release;Prerelease @@ -20,8 +20,8 @@ true MIT Shared Library for IW4MAdmin - 2.2.5.0 - 2.2.5.0 + 2.2.6.0 + 2.2.6.0 diff --git a/WebfrontCore/Controllers/HomeController.cs b/WebfrontCore/Controllers/HomeController.cs index 54e095ca2..70fd16694 100644 --- a/WebfrontCore/Controllers/HomeController.cs +++ b/WebfrontCore/Controllers/HomeController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using SharedLibraryCore; using SharedLibraryCore.Dtos; using SharedLibraryCore.Interfaces; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -10,9 +11,11 @@ namespace WebfrontCore.Controllers { public class HomeController : BaseController { - public HomeController(IManager manager) : base(manager) - { + private readonly IPluginImporter _pluginImporter; + public HomeController(IManager manager, IPluginImporter importer) : base(manager) + { + _pluginImporter = importer; } public async Task Index() @@ -65,7 +68,7 @@ namespace WebfrontCore.Controllers var pluginType = _cmd.GetType().Assembly.GetTypes().FirstOrDefault(_type => _type.Assembly != excludedAssembly && typeof(IPlugin).IsAssignableFrom(_type)); return pluginType == null ? Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_HELP_COMMAND_NATIVE"] : - SharedLibraryCore.Plugins.PluginImporter.ActivePlugins.First(_plugin => _plugin.GetType() == pluginType).Name; // for now we're just returning the name of the plugin, maybe later we'll include more info + _pluginImporter.ActivePlugins.First(_plugin => _plugin.GetType() == pluginType).Name; // for now we're just returning the name of the plugin, maybe later we'll include more info }) .Select(_grp => (_grp.Key, _grp.AsEnumerable())); diff --git a/WebfrontCore/Program.cs b/WebfrontCore/Program.cs index c37c5f738..18a9c256b 100644 --- a/WebfrontCore/Program.cs +++ b/WebfrontCore/Program.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; @@ -11,15 +12,17 @@ namespace WebfrontCore public class Program { public static IManager Manager; + public static IServiceProvider ApplicationServiceProvider; static void Main() { - throw new System.Exception("Webfront core cannot be run as a standalone application"); + throw new Exception("Webfront core cannot be run as a standalone application"); } - public static Task Init(IManager mgr, CancellationToken cancellationToken) + public static Task Init(IManager mgr, IServiceProvider existingServiceProvider, CancellationToken cancellationToken) { Manager = mgr; + ApplicationServiceProvider = existingServiceProvider; var config = Manager.GetApplicationSettings().Configuration(); Manager.MiddlewareActionHandler.Register(null, new CustomCssAccentMiddlewareAction("#007ACC", "#fd7e14", config.WebfrontPrimaryColor, config.WebfrontSecondaryColor), "custom_css_accent"); return BuildWebHost().RunAsync(cancellationToken); diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs index 1ffedd01a..eb1d3401e 100644 --- a/WebfrontCore/Startup.cs +++ b/WebfrontCore/Startup.cs @@ -17,16 +17,6 @@ namespace WebfrontCore { public class Startup { - public static IConfigurationRoot Configuration { get; private set; } - - public Startup(IWebHostEnvironment env) - { - var builder = new ConfigurationBuilder() - .AddEnvironmentVariables(); - - Configuration = builder.Build(); - } - // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { @@ -93,6 +83,7 @@ namespace WebfrontCore #endif services.AddSingleton(Program.Manager); + services.AddSingleton(Program.ApplicationServiceProvider.GetService(typeof(IPluginImporter)) as IPluginImporter); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/WebfrontCore/Views/Home/Help.cshtml b/WebfrontCore/Views/Home/Help.cshtml index 5c3a25ab2..4e8cfef59 100644 --- a/WebfrontCore/Views/Home/Help.cshtml +++ b/WebfrontCore/Views/Home/Help.cshtml @@ -1,4 +1,4 @@ -@model IEnumerable<(string, IEnumerable)> +@model IEnumerable<(string, IEnumerable)> @{ var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex; } diff --git a/version.txt b/version.txt index 4c8cd6c10..a9b98aadf 100644 --- a/version.txt +++ b/version.txt @@ -1,16 +1,16 @@ -Version 2.4: +Version 2.3: -added "live radar" feature -added chat message to server on server list view -added recently connected players dropdown option on webfront -added "dashboard" to home view with quick stats -added ability to customize accent color and branding on webfront -added flag button to client profile --hid flagged status of users on webfront unless logged in +-added ability to specify permission levels per command -added snap anticheat metric - -Version 2.3: -added configuration option to ignore bots -updated anticheat slightly +-hides flagged status of users on webfront unless logged in +-updated projects to .NET Core 3.1 -lots more Version 2.2: