From 420e25d682aae2201e87f263c07ee5a4b464e17e Mon Sep 17 00:00:00 2001 From: Brett Hewitson Date: Sun, 15 Nov 2020 11:22:22 +1000 Subject: [PATCH] Removed source code --- .../Delegates/FetchProfilesDelegate.cs | 7 - .../Plugin.Common/Enums/AlertTypeEnum.cs | 15 - .../Plugin.Common/Extensions/IconExtension.cs | 47 --- .../Plugin.Common/Interfaces/IAlertPlugin.cs | 13 - .../source/Plugin.Common/Interfaces/IBeta.cs | 11 - .../Plugin.Common/Interfaces/IPlugin.cs | 56 --- .../source/Plugin.Common/Lib/Profile.cs | 8 - .../source/Plugin.Common/Plugin.Common.csproj | 24 -- .../source/Plugin.Common/PluginException.cs | 30 -- .../source/Plugin.Common/PluginHelper.cs | 305 -------------- .../source/Plugin.Common/PluginItem.cs | 27 -- .../Plugin.Common/Properties/AssemblyInfo.cs | 34 -- .../source/Plugin.Common/Utils/JsonUtils.cs | 64 --- .../Plugin.Common/Utils/ResourceUtils.cs | 25 -- .../Discord/source/Plugin.Discord/Art/Add.ico | Bin 102134 -> 0 bytes .../source/Plugin.Discord/Art/ChangeNotes.ico | Bin 102134 -> 0 bytes .../source/Plugin.Discord/Art/Delete.ico | Bin 102134 -> 0 bytes .../source/Plugin.Discord/Art/Download.ico | Bin 102134 -> 0 bytes .../source/Plugin.Discord/Art/Drag.ico | Bin 102134 -> 0 bytes .../source/Plugin.Discord/Art/Edit.ico | Bin 102134 -> 0 bytes .../source/Plugin.Discord/Art/favicon.ico | Bin 15086 -> 0 bytes .../source/Plugin.Discord/Config.Designer.cs | 158 -------- .../source/Plugin.Discord/Config.settings | 48 --- .../source/Plugin.Discord/DiscordPlugin.cs | 260 ------------ .../Globalization/en-US/en-US.xaml | 119 ------ .../Plugin.Discord/Interfaces/IBindable.cs | 15 - .../Plugin.Discord/Lib/BrowserBehavior.cs | 32 -- .../Plugin.Discord/Models/AlertTypeValue.cs | 55 --- .../Models/AlertTypeValueList.cs | 69 ---- .../source/Plugin.Discord/Models/Bindable.cs | 85 ---- .../Plugin.Discord/Models/ComboBoxItem.cs | 56 --- .../Plugin.Discord/Models/ComboBoxItemList.cs | 11 - .../Plugin.Discord/Models/ConfigProfile.cs | 188 --------- .../Models/DiscordPluginConfig.cs | 35 -- .../Plugin.Discord/Models/ObservableList.cs | 142 ------- .../Plugin.Discord/Models/ProfileNameValue.cs | 54 --- .../Models/ProfileNameValueList.cs | 67 ---- .../Plugin.Discord/Models/VersionFeed.cs | 16 - .../Plugin.Discord/Models/VersionFeedEntry.cs | 17 - .../Plugin.Discord/Plugin.Discord.csproj | 75 ---- .../Plugin.Discord/Properties/AssemblyInfo.cs | 34 -- .../Plugin.Discord/Utils/NetworkUtils.cs | 90 ----- .../source/Plugin.Discord/Utils/TaskUtils.cs | 15 - .../Plugin.Discord/Utils/VersionFeedUtils.cs | 53 --- .../Plugin.Discord/Utils/WindowUtils.cs | 122 ------ .../source/Plugin.Discord/VersionFeed.xml | 316 --------------- .../source/Plugin.Discord/VersionFeedBeta.xml | 56 --- .../Windows/ConfigProfileWindow.xaml | 235 ----------- .../Windows/ConfigProfileWindow.xaml.cs | 320 --------------- .../Plugin.Discord/Windows/ConfigWindow.xaml | 147 ------- .../Windows/ConfigWindow.xaml.cs | 377 ------------------ .../Windows/VersionFeedWindow.xaml | 60 --- .../Windows/VersionFeedWindow.xaml.cs | 81 ---- .../Discord/source/Plugin.Discord/app.config | 54 --- .../source/ServerManagerTool.Plugins.sln | 43 -- 55 files changed, 4171 deletions(-) delete mode 100644 Plugins/Discord/source/Plugin.Common/Delegates/FetchProfilesDelegate.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Enums/AlertTypeEnum.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Extensions/IconExtension.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Interfaces/IAlertPlugin.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Interfaces/IBeta.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Interfaces/IPlugin.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Lib/Profile.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Plugin.Common.csproj delete mode 100644 Plugins/Discord/source/Plugin.Common/PluginException.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/PluginHelper.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/PluginItem.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Properties/AssemblyInfo.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Utils/JsonUtils.cs delete mode 100644 Plugins/Discord/source/Plugin.Common/Utils/ResourceUtils.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/Add.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/ChangeNotes.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/Delete.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/Download.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/Drag.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/Edit.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Art/favicon.ico delete mode 100644 Plugins/Discord/source/Plugin.Discord/Config.Designer.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Config.settings delete mode 100644 Plugins/Discord/source/Plugin.Discord/DiscordPlugin.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Globalization/en-US/en-US.xaml delete mode 100644 Plugins/Discord/source/Plugin.Discord/Interfaces/IBindable.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Lib/BrowserBehavior.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValue.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValueList.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/Bindable.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItem.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItemList.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/ConfigProfile.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/DiscordPluginConfig.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/ObservableList.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValue.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValueList.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/VersionFeed.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Models/VersionFeedEntry.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Plugin.Discord.csproj delete mode 100644 Plugins/Discord/source/Plugin.Discord/Properties/AssemblyInfo.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Utils/NetworkUtils.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Utils/TaskUtils.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Utils/VersionFeedUtils.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Utils/WindowUtils.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/VersionFeed.xml delete mode 100644 Plugins/Discord/source/Plugin.Discord/VersionFeedBeta.xml delete mode 100644 Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml delete mode 100644 Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Windows/ConfigWindow.xaml delete mode 100644 Plugins/Discord/source/Plugin.Discord/Windows/ConfigWindow.xaml.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/Windows/VersionFeedWindow.xaml delete mode 100644 Plugins/Discord/source/Plugin.Discord/Windows/VersionFeedWindow.xaml.cs delete mode 100644 Plugins/Discord/source/Plugin.Discord/app.config delete mode 100644 Plugins/Discord/source/ServerManagerTool.Plugins.sln diff --git a/Plugins/Discord/source/Plugin.Common/Delegates/FetchProfilesDelegate.cs b/Plugins/Discord/source/Plugin.Common/Delegates/FetchProfilesDelegate.cs deleted file mode 100644 index 32ef73f5..00000000 --- a/Plugins/Discord/source/Plugin.Common/Delegates/FetchProfilesDelegate.cs +++ /dev/null @@ -1,7 +0,0 @@ -using ServerManagerTool.Plugin.Common.Lib; -using System.Collections.Generic; - -namespace ServerManagerTool.Plugin.Common.Delegates -{ - public delegate IList FetchProfilesDelegate(); -} diff --git a/Plugins/Discord/source/Plugin.Common/Enums/AlertTypeEnum.cs b/Plugins/Discord/source/Plugin.Common/Enums/AlertTypeEnum.cs deleted file mode 100644 index ff88e7af..00000000 --- a/Plugins/Discord/source/Plugin.Common/Enums/AlertTypeEnum.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ServerManagerTool.Plugin.Common -{ - public enum AlertType - { - Error, - Shutdown, - ShutdownMessage, - ShutdownReason, - Startup, - Backup, - UpdateResults, - ServerStatusChange, - ModUpdateDetected, - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Extensions/IconExtension.cs b/Plugins/Discord/source/Plugin.Common/Extensions/IconExtension.cs deleted file mode 100644 index b838d14a..00000000 --- a/Plugins/Discord/source/Plugin.Common/Extensions/IconExtension.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Linq; -using System.Windows.Markup; -using System.Windows.Media.Imaging; - -namespace ServerManagerTool.Plugin.Common -{ - /// - /// Simple extension for icon, to let you choose icon with specific size. - /// Usage sample: - /// Image Stretch="None" Source="{common:Icon /Controls;component/icons/custom.ico, 16}" - /// Or: - /// Image Source="{common:Icon Source={Binding IconResource}, Size=16}" - /// - public class IconExtension : MarkupExtension - { - private string _path; - - public string Path - { - get - { - return _path; - } - set - { - // Have to make full pack URI from short form, so System.Uri recognizes it. - _path = $"pack://application:,,,{value}"; - } - } - - public int Size { get; set; } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - var decoder = BitmapDecoder.Create(new Uri(Path), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand); - - var result = decoder.Frames.SingleOrDefault(f => f.Width == Size); - if (result == default(BitmapFrame)) - { - result = decoder.Frames.OrderBy(f => f.Width).First(); - } - - return result; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Interfaces/IAlertPlugin.cs b/Plugins/Discord/source/Plugin.Common/Interfaces/IAlertPlugin.cs deleted file mode 100644 index 1fde0a56..00000000 --- a/Plugins/Discord/source/Plugin.Common/Interfaces/IAlertPlugin.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ServerManagerTool.Plugin.Common -{ - public interface IAlertPlugin : IPlugin - { - /// - /// Handles the alert message passed for the profile. - /// - /// The type of alert message. - /// The name of the profile the alert message is associated with. - /// The message of the alert. - void HandleAlert(AlertType alertType, string profileName, string alertMessage); - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Interfaces/IBeta.cs b/Plugins/Discord/source/Plugin.Common/Interfaces/IBeta.cs deleted file mode 100644 index 964c32f8..00000000 --- a/Plugins/Discord/source/Plugin.Common/Interfaces/IBeta.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ServerManagerTool.Plugin.Common -{ - public interface IBeta - { - bool BetaEnabled - { - get; - set; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Interfaces/IPlugin.cs b/Plugins/Discord/source/Plugin.Common/Interfaces/IPlugin.cs deleted file mode 100644 index 9585bc65..00000000 --- a/Plugins/Discord/source/Plugin.Common/Interfaces/IPlugin.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Windows; - -namespace ServerManagerTool.Plugin.Common -{ - public interface IPlugin - { - /// - /// Gets a values indicating if the plugin can be used - /// - bool Enabled - { - get; - } - /// - /// Gets a value indicating the code of the plugin - /// - string PluginCode - { - get; - } - /// - /// Gets a value indicating the name of the plugin - /// - string PluginName - { - get; - } - /// - /// Gets a value indicating the version of the plugin - /// - Version PluginVersion - { - get; - } - - /// - /// Gets a value that indicates if the plugin has a configuration form. - /// - bool HasConfigForm - { - get; - } - - /// - /// Performs any initialization for the plugin. - /// - void Initialize(); - - /// - /// Opens the configuration form. - /// - /// The owner window. - void OpenConfigForm(Window owner); - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Lib/Profile.cs b/Plugins/Discord/source/Plugin.Common/Lib/Profile.cs deleted file mode 100644 index f99c0a68..00000000 --- a/Plugins/Discord/source/Plugin.Common/Lib/Profile.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ServerManagerTool.Plugin.Common.Lib -{ - public class Profile - { - public string ProfileName { get; set; } - public string InstallationFolder { get; set; } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Plugin.Common.csproj b/Plugins/Discord/source/Plugin.Common/Plugin.Common.csproj deleted file mode 100644 index 70274438..00000000 --- a/Plugins/Discord/source/Plugin.Common/Plugin.Common.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - %24/Development/ServerManagers/Main/Plugin.Common - {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} - https://dev.azure.com/bretthewitson - . - - - net462 - false - ServerManagerTool.Plugin.Common - ServerManager.Plugin.Common - - - none - false - - - - - - - - \ No newline at end of file diff --git a/Plugins/Discord/source/Plugin.Common/PluginException.cs b/Plugins/Discord/source/Plugin.Common/PluginException.cs deleted file mode 100644 index 15c6fa78..00000000 --- a/Plugins/Discord/source/Plugin.Common/PluginException.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Runtime.Serialization; -using System.Security; - -namespace ServerManagerTool.Plugin.Common -{ - public class PluginException : Exception - { - public PluginException() - : base() - { - } - - public PluginException(string message) - : base(message) - { - } - - public PluginException(string message, Exception innerException) - : base(message, innerException) - { - } - - [SecuritySafeCritical] - protected PluginException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/PluginHelper.cs b/Plugins/Discord/source/Plugin.Common/PluginHelper.cs deleted file mode 100644 index 20c1ea03..00000000 --- a/Plugins/Discord/source/Plugin.Common/PluginHelper.cs +++ /dev/null @@ -1,305 +0,0 @@ -using ServerManagerTool.Plugin.Common.Delegates; -using ServerManagerTool.Plugin.Common.Lib; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Windows; - -namespace ServerManagerTool.Plugin.Common -{ - public sealed class PluginHelper : IDisposable - { - private const string PLUGINFILE_FOLDER = "Plugins"; - private const string PLUGINFILE_EXTENSION = "dll"; - - private static volatile PluginHelper _instance; - private static readonly object _syncLock = new object(); - - private readonly Object _syncLockProcessAlert = new Object(); - private readonly Object _syncLockFetchProfiles = new Object(); - private FetchProfilesDelegate _fetchProfilesCallback; - private bool _disposed; - - private PluginHelper() - { - BetaEnabled = false; - Plugins = new ObservableCollection(); - } - - public static PluginHelper Instance - { - get - { - if (_instance != null) - return _instance; - - lock(_syncLock) - { - if (_instance == null) - _instance = new PluginHelper(); - } - return _instance; - } - } - - public static string PluginFolder - { - get - { - var folder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location ?? Environment.CurrentDirectory); - return Path.Combine(folder, PLUGINFILE_FOLDER); - } - } - - internal bool BetaEnabled - { - get; - set; - } - - public ObservableCollection Plugins - { - get; - private set; - } - - internal void AddPlugin(string folder, string pluginFile) - { - if (!CheckPluginFile(pluginFile)) - throw new PluginException("The selected file does not contain server manager plugins or is for a previous version of server manager."); - - var pluginFolder = Path.Combine(folder, PLUGINFILE_FOLDER); - if (!Directory.Exists(pluginFolder)) - Directory.CreateDirectory(pluginFolder); - - var newPluginFile = Path.Combine(pluginFolder, $"{Path.GetFileName(pluginFile)}"); - if (File.Exists(newPluginFile)) - throw new PluginException("A file with the same name already exists, delete the existing file and try again."); - - File.Copy(pluginFile, newPluginFile, true); - - LoadPlugin(newPluginFile); - } - - internal bool CheckPluginFile(string pluginFile) - { - if (string.IsNullOrWhiteSpace(pluginFile)) - return false; - if (!File.Exists(pluginFile)) - return false; - - Assembly assembly = Assembly.Load(File.ReadAllBytes(pluginFile)); - if (assembly == null) - return false; - - Type[] types; - - try - { - types = assembly.GetTypes(); - } - catch - { - return false; - } - - if (types.Length == 0) - return false; - - // check if the file contains a plugin - foreach (Type type in types) - { - if (type.GetInterface(typeof(IPlugin).Name) != null) - return true; - } - - return false; - } - - internal void DeleteAllPlugins() - { - for (int index = Plugins.Count - 1; index >= 0; index--) - { - var pluginFile = Plugins[index].PluginFile; - - Plugins.RemoveAt(index); - - if (File.Exists(pluginFile)) - File.Delete(pluginFile); - } - } - - internal void DeletePlugin(string pluginFile) - { - if (string.IsNullOrWhiteSpace(pluginFile)) - return; - - for (int index = Plugins.Count - 1; index >= 0; index--) - { - if (Plugins[index].PluginFile.Equals(pluginFile, StringComparison.OrdinalIgnoreCase)) - Plugins.RemoveAt(index); - } - - if (File.Exists(pluginFile)) - File.Delete(pluginFile); - } - - public IList FetchProfileList() - { - lock (_syncLockFetchProfiles) - { - return _fetchProfilesCallback?.Invoke() ?? new List(); - } - } - - internal void LoadPlugin(string pluginFile) - { - if (string.IsNullOrWhiteSpace(pluginFile)) - return; - if (!File.Exists(pluginFile)) - return; - - Assembly assembly = Assembly.Load(File.ReadAllBytes(pluginFile)); - if (assembly == null) - return; - - Type[] types; - - try - { - types = assembly.GetTypes(); - } - catch - { - return; - } - - if (types.Length == 0) - return; - - // check if the file contains one or more plugins - foreach (Type type in types) - { - try - { - if (type.GetInterface(typeof(IAlertPlugin).Name) != null) - { - var plugin = assembly.CreateInstance(type.FullName) as IAlertPlugin; - if (plugin != null && plugin.Enabled) - { - if (type.GetInterface(typeof(IBeta).Name) != null) - ((IBeta)plugin).BetaEnabled = BetaEnabled; - plugin.Initialize(); - - Plugins.Add(new PluginItem { Plugin = plugin, PluginFile = pluginFile, PluginType = nameof(IAlertPlugin) }); - } - } - else if (type.GetInterface(typeof(IPlugin).Name) != null) - { - var plugin = assembly.CreateInstance(type.FullName) as IPlugin; - if (plugin != null && plugin.Enabled) - { - if (type.GetInterface(typeof(IBeta).Name) != null) - ((IBeta)plugin).BetaEnabled = BetaEnabled; - plugin.Initialize(); - - Plugins.Add(new PluginItem { Plugin = plugin, PluginFile = pluginFile, PluginType = nameof(IPlugin) }); - } - } - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(LoadPlugin)} - {type.FullName}\r\n{ex.Message}"); - } - } - } - - internal void LoadPlugins(string folder, bool ClearExisting) - { - if (ClearExisting) - Plugins.Clear(); - - var pluginFolder = Path.Combine(folder, PLUGINFILE_FOLDER); - if (string.IsNullOrWhiteSpace(pluginFolder)) - return; - if (!Directory.Exists(pluginFolder)) - return; - - var pluginFiles = Directory.GetFiles(pluginFolder, $"*.{PLUGINFILE_EXTENSION}"); - foreach (var pluginFile in pluginFiles) - { - LoadPlugin(pluginFile); - } - } - - internal void OpenConfigForm(string pluginCode, Window owner) - { - if (Plugins == null) - return; - - var pluginItem = Plugins.FirstOrDefault(p => p.Plugin.PluginCode.Equals(pluginCode, StringComparison.OrdinalIgnoreCase)); - OpenConfigForm(pluginItem.Plugin, owner); - } - - internal void OpenConfigForm(IPlugin plugin, Window owner) - { - if (plugin == null || !plugin.Enabled || !plugin.HasConfigForm) - return; - - plugin.OpenConfigForm(owner); - } - - internal bool ProcessAlert(AlertType alertType, string profileName, string alertMessage) - { - if (Plugins == null || Plugins.Count == 0 || string.IsNullOrWhiteSpace(alertMessage)) - return false; - - var plugins = Plugins.Where(p => (p.PluginType is nameof(IAlertPlugin)) && (p.Plugin?.Enabled ?? false)); - if (plugins.Count() == 0) - return false; - - lock (_syncLockProcessAlert) - { - var message = alertMessage.Replace("\\r\\n", "\\n"); - message = message.Replace("\\n", "\n"); - - foreach (var pluginItem in plugins) - { - ((IAlertPlugin)pluginItem.Plugin).HandleAlert(alertType, profileName, message.ToString()); - } - } - - return true; - } - - internal void SetFetchProfileCallback(FetchProfilesDelegate callback) - { - _fetchProfilesCallback = callback; - } - - public void Dispose() - { - Dispose(true); - - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - _fetchProfilesCallback = null; - _instance = null; - } - - _disposed = true; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/PluginItem.cs b/Plugins/Discord/source/Plugin.Common/PluginItem.cs deleted file mode 100644 index 5c2bdcec..00000000 --- a/Plugins/Discord/source/Plugin.Common/PluginItem.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace ServerManagerTool.Plugin.Common -{ - public sealed class PluginItem - { - internal PluginItem() - { - } - - public IPlugin Plugin - { - get; - set; - } - - public string PluginFile - { - get; - set; - } - - public string PluginType - { - get; - set; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Properties/AssemblyInfo.cs b/Plugins/Discord/source/Plugin.Common/Properties/AssemblyInfo.cs deleted file mode 100644 index f5474544..00000000 --- a/Plugins/Discord/source/Plugin.Common/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServerManager Common Plugin Library")] -[assembly: AssemblyDescription("The library is used to provide common plugin functionality to the server managers.")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Bletch1971")] -[assembly: AssemblyProduct("Server Managers")] -[assembly: AssemblyCopyright("Copyright © 2015-2020")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("679fe859-9a82-4ffb-a758-c1e8df915f58")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.1.0")] -[assembly: AssemblyFileVersion("1.0.1.0")] diff --git a/Plugins/Discord/source/Plugin.Common/Utils/JsonUtils.cs b/Plugins/Discord/source/Plugin.Common/Utils/JsonUtils.cs deleted file mode 100644 index f969488b..00000000 --- a/Plugins/Discord/source/Plugin.Common/Utils/JsonUtils.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.IO; -using System.Runtime.Serialization.Json; - -namespace ServerManagerTool.Plugin.Common -{ - public static class JsonUtils - { - public static T DeserializeFromFile(string file) - { - if (string.IsNullOrEmpty(file) || !File.Exists(file)) - return default(T); - - StreamReader streamReader = null; - - try - { - streamReader = File.OpenText(file); - - Data​Contract​Json​Serializer serializer = new DataContractJsonSerializer(typeof(T)); - return (T)serializer.ReadObject(streamReader.BaseStream); - } - catch - { - return default(T); - } - finally - { - if (streamReader != null) - streamReader.Close(); - } - } - - public static bool SerializeToFile(T value, string file) - { - if (value == null) - return false; - - StreamWriter streamWriter = null; - - try - { - var folder = Path.GetDirectoryName(file); - if (!Directory.Exists(folder)) - Directory.CreateDirectory(folder); - - streamWriter = File.CreateText(file); - - Data​Contract​Json​Serializer serializer = new DataContractJsonSerializer(typeof(T)); - serializer.WriteObject(streamWriter.BaseStream, value); - - return true; - } - catch - { - return false; - } - finally - { - if (streamWriter != null) - streamWriter.Close(); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Common/Utils/ResourceUtils.cs b/Plugins/Discord/source/Plugin.Common/Utils/ResourceUtils.cs deleted file mode 100644 index 18b9ae62..00000000 --- a/Plugins/Discord/source/Plugin.Common/Utils/ResourceUtils.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Windows; - -namespace ServerManagerTool.Plugin.Common -{ - public static class ResourceUtils - { - public static string GetResourceString(ResourceDictionary resources, string inKey) - { - if (resources == null) - throw new ArgumentNullException(nameof(resources), "parameter cannot be null."); - if (string.IsNullOrWhiteSpace(inKey)) - throw new ArgumentNullException(nameof(inKey), "parameter cannot be null."); - - if (resources.Contains(inKey) && resources[inKey] is string) - { - var resourceString = resources[inKey].ToString(); - resourceString = resourceString.Replace("\\r", "\r"); - resourceString = resourceString.Replace("\\n", "\n"); - return resourceString; - } - return null; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Art/Add.ico b/Plugins/Discord/source/Plugin.Discord/Art/Add.ico deleted file mode 100644 index f5b8bc3e20dbad3c30f828e813f16c7f65bd4bcf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102134 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 U?@jBE&!qL&x6}IbvHt%50etm6&;S4c diff --git a/Plugins/Discord/source/Plugin.Discord/Art/ChangeNotes.ico b/Plugins/Discord/source/Plugin.Discord/Art/ChangeNotes.ico deleted file mode 100644 index 8124758222c4eae979b208614d514cf87ff9d383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102134 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 E0i9@WlK=n! diff --git a/Plugins/Discord/source/Plugin.Discord/Art/favicon.ico b/Plugins/Discord/source/Plugin.Discord/Art/favicon.ico deleted file mode 100644 index 1ce0205a3ac78c1b8258bf04410eee49827f6c7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 zcmeI3U1(d^9l(!2GOuf>g`3oI>{yCz*_I_+viu?WOO_pf${*Dp%IN5W*ce-34}J+5 zWe|-%xRgQIL*K&07!7+^F=KR$QD%pB>nIC)NkZt0otH7T1=*knL1Lf%j&!ect;n*Z z>cgeJ@bmxPbN=W2&po=n_uT*ge}$+LHNs>PNQ?MMtq{XP2#Y0k{5#5jO_|H39b1K% zyC_6AI#kgjRgMq>y@r=lB#$fb=R#xK#aCau`bXr=e9bpCce*cKwmxpW-0>TTvmeT( zkE*I_am8%=eoJe29At~R`?v6*xwZS9liIggd#kT@^uA|lcSr;K<~I9{+H>E^+Purw zZ|dxJ{mI(plm=q$oqd6-s;aDQ?Y)Dx9>>6=9{YgQvDpV6cK5h#*&3>TUH#rbpUblc z@(}0n$Bw=sbxFLi4GxdLH83>xXZUb%XzZ5*gQNQ(b=(6Z@AbP!s$XbGfp^5W>>2UN zV~7uXCf=;6;lev+8=sgC!`|4q|9h}FJ~8z_jwSLj$L^EnY0^J44|ctK|J3Y_si|2B z>v~zPa(-c{c5ZI*&g|Txgb#CVr}UPVR~rILE1v`cD-xbAE-o+U(|%>;brbv)-T`}c zb;jw=r^}plr4&N$!47Nzm*qi?5YOs_NYo1vHq(vzPerdE9>ZPu6jWPvpRs@+)cq;B zag|m2K9d^AH|uX>bGP8$8i3pIV`wPX3|wq%tL2{lUHBJBh{LbSVV~zf1J8pGUTbQP z!xPvBsi6D@_2)`8j;5B*CZ0>TFEv}Ag2dLl*c@X2e)724`jC1@vF-Exs^wWW(tM@s zK1c%}QEq8&?Ygd&{rmEjE?+V2H#N75D;C=u@QCNCOe0SD7qG3$TgJkYJ2&TH5Taw!ZrI>V->!^}|?4 zXWu_SW`niGXYJNLU*o0LuWnfDfpv@@zGN-44>AjzjMLiD=`6~_i}laTta*NJ>v8Xa zJPy`Gaad=JMZ4cQdWRZVgRR>ggK>~qc)~b;X0yAC@>@Gyo@&-?)?VlE=ODAN-`h9z zC2KnWpl7mZzcp(|AAIKQ_sXoeJa_w?!(;gxW{r7{b)^G-2w`{|rYLVghFEJRKxQG{ zKQMBK^=RGs^RMJRGl^XlV|5EmM!z|-e-hdPw`Z==&xSNH7`EM%{q@LjXR1Ca1J?-w@gCGS)0U!3qwf2`H1 zdPSV~kPpzw`?tYLqs-y=&pZUFaSz#kRIBhK-iywG4>I1Trl#i_ zr>E!cg4FmA(qFj6+*{Vv)QH*H#jcszg?k_kypek^g=_NO_saZy;G?JcDVmy!?7C z@44f!0a17WU%)zay!6s{GBqoD+3ITWJXpaFmZBRt>o7S3^7-~DyERfC;6Hct4d0$wnQD&<8heOkg}SpdRmwv*(359Bw)9m{mJJ>m7f9^sR+TL zpQ7W;Pr-DYZQr07z$fH~u##W5(`L-KKpKdA9nJyYm0(Px>K7)h(!(CaEG z@j06CH%35aU|S#C<(5vRXVlr$>nbJjsao(CMnPsFf}S7Nj5_!@D?0zJmL5Mo*BHpW zG25c}YBR!EaiC9`}X;+g+b~N3l692=*QHBbiH&* zU6i=8OV=%zB$gZk2{E;Ql3jEnn!ajdq^$F86u(^!n**^L~&Si0V40S==2jeKttx!#*v&bP|@KEi1pKY0rl z@)n{XGeQ2ssl9&4E%1}$5CeHE3rpeCIRE5qtZ8}vD%U?Fi-F}B=a}<7pj_ukzDERP zR+dyw$VyK4-g1pw*&$~{eIpTu7|0B$^03k?=eY8k?Lnl zr1}ku$)sNLdn=V6Rh6`#5H(4;O9qsx-$`acVI`RfrN($ul^>`&zTFz98FE*kj@%Kb zBe#SwD;ZV^R4I8gB~e$$J1U7vh%yWsdp- PWlrh+0-d diff --git a/Plugins/Discord/source/Plugin.Discord/Config.Designer.cs b/Plugins/Discord/source/Plugin.Discord/Config.Designer.cs deleted file mode 100644 index fc944820..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Config.Designer.cs +++ /dev/null @@ -1,158 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ServerManagerTool.Plugin.Discord { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] - internal sealed partial class Config : global::System.Configuration.ApplicationSettingsBase { - - private static Config defaultInstance = ((Config)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Config()))); - - public static Config Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("http://servermanager.azurewebsites.net/api/plugin/call/{0}/{1}/")] - public string PluginCallUrlFormat { - get { - return ((string)(this["PluginCallUrlFormat"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("http://whatismyip.akamai.com/")] - public string PublicIPCheckUrl { - get { - return ((string)(this["PublicIPCheckUrl"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("12")] - public int CallHomeDelay { - get { - return ((int)(this["CallHomeDelay"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("5000")] - public int RequestTimeout { - get { - return ((int)(this["RequestTimeout"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("1B745000-6389-4770-9509-C6A05E209323")] - public string PluginCode { - get { - return ((string)(this["PluginCode"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("Discord Plugin")] - public string PluginName { - get { - return ((string)(this["PluginName"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discor" + - "d/latest.zip")] - public string LatestDownloadUrl { - get { - return ((string)(this["LatestDownloadUrl"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discor" + - "d/latest.txt")] - public string LatestVersionUrl { - get { - return ((string)(this["LatestVersionUrl"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discor" + - "d/beta/latest.zip")] - public string LatestBetaDownloadUrl { - get { - return ((string)(this["LatestBetaDownloadUrl"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discor" + - "d/beta/latest.txt")] - public string LatestBetaVersionUrl { - get { - return ((string)(this["LatestBetaVersionUrl"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("ServerManager.Plugin.Discord.zip")] - public string PluginZipFilename { - get { - return ((string)(this["PluginZipFilename"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("_discordplugin.cfg")] - public string ConfigFile { - get { - return ((string)(this["ConfigFile"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discor" + - "d/VersionFeed.xml")] - public string VersionFeedUrl { - get { - return ((string)(this["VersionFeedUrl"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discor" + - "d/beta/VersionFeed.xml")] - public string VersionBetaFeedUrl { - get { - return ((string)(this["VersionBetaFeedUrl"])); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Config.settings b/Plugins/Discord/source/Plugin.Discord/Config.settings deleted file mode 100644 index e95f2570..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Config.settings +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - http://servermanager.azurewebsites.net/api/plugin/call/{0}/{1}/ - - - http://whatismyip.akamai.com/ - - - 12 - - - 5000 - - - 1B745000-6389-4770-9509-C6A05E209323 - - - Discord Plugin - - - https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discord/latest.zip - - - https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discord/latest.txt - - - https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discord/beta/latest.zip - - - https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discord/beta/latest.txt - - - ServerManager.Plugin.Discord.zip - - - _discordplugin.cfg - - - https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discord/VersionFeed.xml - - - https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/Plugins/Discord/beta/VersionFeed.xml - - - \ No newline at end of file diff --git a/Plugins/Discord/source/Plugin.Discord/DiscordPlugin.cs b/Plugins/Discord/source/Plugin.Discord/DiscordPlugin.cs deleted file mode 100644 index f3d3cb91..00000000 --- a/Plugins/Discord/source/Plugin.Discord/DiscordPlugin.cs +++ /dev/null @@ -1,260 +0,0 @@ -using ServerManagerTool.Plugin.Common; -using ServerManagerTool.Plugin.Discord.Windows; -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Windows; - -namespace ServerManagerTool.Plugin.Discord -{ - public sealed class DiscordPlugin : IAlertPlugin, IBeta - { - private const int MAX_MESSAGE_LENGTH = 1980; // 2000 minus some formatting characters - - private Object lockObject = new Object(); - - public DiscordPlugin() - { - BetaEnabled = false; - } - - private DiscordPluginConfig PluginConfig - { - get; - set; - } - - public bool BetaEnabled - { - get; - set; - } - - public bool Enabled => true; - - public string PluginCode => Config.Default.PluginCode; - - public string PluginName => Config.Default.PluginName; - - public Version PluginVersion - { - get - { - try - { - return Assembly.GetExecutingAssembly().GetName().Version; - } - catch - { - return new Version(); - } - } - } - - public bool HasConfigForm => true; - - private async Task CallHomeAsync() - { - try - { - var publicIP = await NetworkUtils.DiscoverPublicIPAsync(); - await NetworkUtils.PerformCallToAPIAsync(PluginCode, publicIP); -#if DEBUG - var logFile = Path.Combine(PluginHelper.PluginFolder, "DiscordApiCalls.log"); - File.AppendAllLines(logFile, new[] { "CallHomeAsync successful" }, Encoding.Unicode); -#endif - } - catch (Exception ex) - { - Debug.WriteLine($"Failed calling home {ex.Message}"); -#if DEBUG - var logFile = Path.Combine(PluginHelper.PluginFolder, "DiscordErrors.log"); - File.AppendAllLines(logFile, new[] { $"Failed calling home {ex.Message}" }, Encoding.Unicode); -#endif - } - } - - public void HandleAlert(AlertType alertType, string profileName, string alertMessage) - { - if (string.IsNullOrWhiteSpace(alertMessage)) - return; - - lock (lockObject) - { - var configProfiles = PluginConfig.ConfigProfiles.Where(cp => cp.IsEnabled - && cp.AlertTypes.Any(pn => pn.Value.Equals(alertType)) - && cp.ProfileNames.Any(pn => pn.Value.Equals(profileName, StringComparison.OrdinalIgnoreCase)) - && !string.IsNullOrWhiteSpace(cp.DiscordWebhookUrl)); - if (configProfiles == null || configProfiles.Count() == 0) - { -#if DEBUG - var logFile = Path.Combine(PluginHelper.PluginFolder, "DiscordErrors.log"); - File.AppendAllLines(logFile, new[] { $"{alertType}; {profileName} - {alertMessage.Replace(Environment.NewLine, " ")} (No config profiles found)" }, Encoding.Unicode); -#endif - return; - } - - foreach (var configProfile in configProfiles) - { - HandleAlert(configProfile, alertType, profileName, alertMessage); - } - } - } - - internal void HandleAlert(ConfigProfile configProfile, AlertType alertType, string profileName, string alertMessage) - { - if (configProfile == null || string.IsNullOrWhiteSpace(configProfile.DiscordWebhookUrl) || string.IsNullOrWhiteSpace(alertMessage)) - return; - - // remove any bad characters - var formattedProfileName = profileName?.Replace("&", "_") ?? string.Empty; - var formattedAlertMessage = alertMessage?.Replace("&", "_") ?? string.Empty; - - // check if we need to add the profile name to the message - if (configProfile.PrefixMessageWithProfileName && !string.IsNullOrWhiteSpace(formattedProfileName)) - formattedAlertMessage = $"({formattedProfileName}) {formattedAlertMessage}"; - - // check if the message is too long - if (formattedAlertMessage.Length > MAX_MESSAGE_LENGTH) - formattedAlertMessage = $"{formattedAlertMessage.Substring(0, MAX_MESSAGE_LENGTH - 3)}..."; - - // check if we need to apply any styles to the message - if (configProfile.MessageCodeBlock) - formattedAlertMessage = $"```{formattedAlertMessage}```"; - if (configProfile.MessageBold) - formattedAlertMessage = $"**{formattedAlertMessage}**"; - if (configProfile.MessageItalic) - formattedAlertMessage = $"*{formattedAlertMessage}*"; - if (configProfile.MessageUnderlined) - formattedAlertMessage = $"__{formattedAlertMessage}__"; - formattedAlertMessage = HttpUtility.UrlEncode(formattedAlertMessage); - - var postData = string.Empty; - - if (configProfile.DiscordUseTTS) - postData += $"&tts={configProfile.DiscordUseTTS}"; - if (!string.IsNullOrWhiteSpace(configProfile.DiscordBotName)) - postData += $"&username={configProfile.DiscordBotName.Replace("&", "_")}"; - postData += $"&content={formattedAlertMessage}"; - - try - { - var data = Encoding.UTF8.GetBytes(postData); - - var url = configProfile.DiscordWebhookUrl; - url = url.Trim(); - if (url.EndsWith("/")) - url = url.Substring(0, url.Length - 1); - - var httpRequest = WebRequest.Create($"{url}?wait=true"); - httpRequest.Timeout = Config.Default.RequestTimeout; - httpRequest.Method = "POST"; - httpRequest.ContentType = "application/x-www-form-urlencoded"; - httpRequest.ContentLength = data.Length; - - using (var stream = httpRequest.GetRequestStream()) - { - stream.Write(data, 0, data.Length); - } - - var httpResponse = (HttpWebResponse)httpRequest.GetResponse(); - var responseString = new StreamReader(httpResponse.GetResponseStream()).ReadToEnd(); - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - Debug.WriteLine($"{nameof(HandleAlert)}\r\nResponse: {responseString}"); -#if DEBUG - var logFile = Path.Combine(PluginHelper.PluginFolder, "DiscordSuccess.log"); - File.AppendAllLines(logFile, new[] { $"{alertType}; {profileName} - {alertMessage.Replace(Environment.NewLine, " ")} ({responseString})" }, Encoding.Unicode); -#endif - } - else - { - Debug.WriteLine($"{nameof(HandleAlert)}\r\n{httpResponse.StatusCode}: {responseString}"); -#if DEBUG - var logFile = Path.Combine(PluginHelper.PluginFolder, "DiscordErrors.log"); - File.AppendAllLines(logFile, new[] { $"{alertType}; {profileName} - {alertMessage.Replace(Environment.NewLine, " ")} ({responseString})" }, Encoding.Unicode); -#endif - } - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(HandleAlert)}\r\n{ex.Message}"); -#if DEBUG - var logFile = Path.Combine(PluginHelper.PluginFolder, "DiscordExceptions.log"); - File.AppendAllLines(logFile, new[] { $"{alertType}; {profileName} - {alertMessage.Replace(Environment.NewLine, " ")} ({ex.Message})" }, Encoding.Unicode); -#endif - } - } - - public void Initialize() - { - LoadConfig(); - - if (PluginConfig.LastCallHome.AddHours(Config.Default.CallHomeDelay) < DateTime.Now) - { - //CallHomeAsync().DoNotWait(); - - PluginConfig.LastCallHome = DateTime.Now; - SaveConfig(); - } - } - - private void LoadConfig() - { - try - { - PluginConfig = null; - - var configFile = Path.Combine(PluginHelper.PluginFolder, Config.Default.ConfigFile); - PluginConfig = JsonUtils.DeserializeFromFile(configFile); - - if ((PluginConfig?.ConfigProfiles?.Count ?? 0) == 0) - { - PluginConfig = new DiscordPluginConfig(); - - SaveConfig(); - } - - PluginConfig?.CommitChanges(); - } - catch (Exception ex) - { - PluginConfig = new DiscordPluginConfig(); - Debug.WriteLine($"ERROR: {nameof(LoadConfig)}\r\n{ex.Message}"); - } - } - - public void OpenConfigForm(Window owner) - { - var window = new ConfigWindow(this, this.PluginConfig); - window.Owner = owner; - - var dialogResult = window.ShowDialog(); - if (dialogResult.HasValue && dialogResult.Value) - { - SaveConfig(); - LoadConfig(); - } - } - - private void SaveConfig() - { - try - { - var configFile = Path.Combine(PluginHelper.PluginFolder, Config.Default.ConfigFile); - JsonUtils.SerializeToFile(PluginConfig, configFile); - PluginConfig?.CommitChanges(); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(SaveConfig)}\r\n{ex.Message}"); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Globalization/en-US/en-US.xaml b/Plugins/Discord/source/Plugin.Discord/Globalization/en-US/en-US.xaml deleted file mode 100644 index 7e86cb25..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Globalization/en-US/en-US.xaml +++ /dev/null @@ -1,119 +0,0 @@ - - - - Cancel - Close - OK - Save - - (Beta Mode) - A new version of the plugin is available. - Download the latest version. - - - - Discord Plugin Configuration - - View the Patch Notes. - Add Profile - Delete All Profiles - Delete Profile - Edit Profile - - Name - - Add Action Error - An error occurred while trying to add a profile. - Confirm Delete All Action - Click 'Yes' to confirm you want to delete all. - Delete All Action Error - An error occurred while trying to delete all profiles. - Confirm Close Action - Click 'Yes' to confirm you want to close the form. If you have any unsaved changes they will be lost. - Confirm Delete Action - Click 'Yes' to confirm you want to perform the delete. - Delete Action Error - An error occurred while trying to delete the profile. - Download Action Error - An error occurred while trying to perform the download. - Download Successful - The latest version has been saved to your desktop. - Edit Action Error - An error occurred while trying to edit a profile. - Save Action Error - An error occurred while trying to perform the save. - - - - Profile Configuration - - Name: - The name of your config profile. - Enabled - Is the config profile enabled. - Webhook Url: - This is your Webhook Url provided by discord. - Bot Name: - This will override the name you setup in your webhook. Leave blank to use default. - Use Text to Speech (TTS) - If enabled, will make the bot announce with Text to Speech, otherwise will turn off Text to Speech. - Prefix Message with Profile Name - If enabled, the alert message will be sent prefixed with the server manager profile name. - Message Options - Bold - If enabled, will show the message in bold. - Underline - If enabled, will show the message with an underline. - Italic - If enabled, will show the message in italic. - Embedded Code Block - CIf enabled, will show the message in an embedded code block. - Profile Names - Alert Types - - Add Server Manager Profile Name - Delete All Server Manager Profile Names - Delete Server Manager Profile Name - - Add Alert Type - Delete All Alert Types - Delete Alert Type - - Server Manager Profile Name - Alert Type - - Test - - Add Action Error - An error occurred while trying to add an alert type. - An error occurred while trying to add a profile name. - Confirm Delete All Action - Click 'Yes' to confirm you want to delete all. - Delete All Action Error - An error occurred while trying to delete all alert types. - An error occurred while trying to delete all profile names. - Confirm Close Action - Click 'Yes' to confirm you want to close the form. If you have any unsaved changes they will be lost. - Confirm Delete Action - Click 'Yes' to confirm you want to perform the delete. - Delete Action Error - An error occurred while trying to delete the alert type. - An error occurred while trying to delete the profile name. - Test Action Error - An error occurred while trying to test the config profile. - The profile is not enabled and cannot be tested. - - - - Discord Plugin Version Details - Load Feed Error - - Version: - Select the version to view details. - - - \ No newline at end of file diff --git a/Plugins/Discord/source/Plugin.Discord/Interfaces/IBindable.cs b/Plugins/Discord/source/Plugin.Discord/Interfaces/IBindable.cs deleted file mode 100644 index 2978db18..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Interfaces/IBindable.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ServerManagerTool.Plugin.Discord -{ - internal interface IBindable - { - bool HasChanges { get; set; } - - bool HasAnyChanges { get; } - - void CommitChanges(); - - void BeginUpdate(); - - void EndUpdate(); - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Lib/BrowserBehavior.cs b/Plugins/Discord/source/Plugin.Discord/Lib/BrowserBehavior.cs deleted file mode 100644 index 6b8e2099..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Lib/BrowserBehavior.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -namespace ServerManagerTool.Plugin.Discord -{ - public static class BrowserBehavior - { - public static readonly DependencyProperty HtmlProperty = DependencyProperty.RegisterAttached("Html", typeof(string), typeof(BrowserBehavior), new FrameworkPropertyMetadata(OnHtmlChanged)); - - [AttachedPropertyBrowsableForType(typeof(WebBrowser))] - public static string GetHtml(WebBrowser d) - { - return (string)d.GetValue(HtmlProperty); - } - - public static void SetHtml(WebBrowser d, string value) - { - d.SetValue(HtmlProperty, value); - } - - static void OnHtmlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (e.NewValue == null) - return; - - if (d is WebBrowser wb) - { - wb.NavigateToString(e.NewValue as string); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValue.cs b/Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValue.cs deleted file mode 100644 index 5d408bd0..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValue.cs +++ /dev/null @@ -1,55 +0,0 @@ -using ServerManagerTool.Plugin.Common; -using System.Runtime.Serialization; - -namespace ServerManagerTool.Plugin.Discord -{ - [DataContract] - internal class AlertTypeValue : Bindable - { - public AlertTypeValue() - : base() - { - Value = AlertType.Error; - OriginalValue = Value; - HasChanges = false; - } - - public AlertTypeValue(AlertType value) - : base() - { - Value = value; - OriginalValue = Value; - HasChanges = !Value.Equals(OriginalValue); - } - - public AlertTypeValue(AlertType value, AlertType originalValue) - : base() - { - Value = value; - OriginalValue = originalValue; - HasChanges = !Value.Equals(OriginalValue); - } - - [DataMember] - public AlertType Value - { - get { return Get(); } - set { Set(value); } - } - - public AlertType OriginalValue - { - get; - set; - } - - public override bool HasAnyChanges => base.HasChanges && !Value.Equals(OriginalValue); - - public override void CommitChanges() - { - base.CommitChanges(); - - OriginalValue = Value; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValueList.cs b/Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValueList.cs deleted file mode 100644 index bbe47fdf..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/AlertTypeValueList.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; - -namespace ServerManagerTool.Plugin.Discord -{ - internal class AlertTypeValueList : List, IBindable, INotifyCollectionChanged - { - private bool _hasChanges = false; - - public bool HasChanges - { - get => _hasChanges; - set => _hasChanges = value; - } - - public bool HasAnyChanges => _hasChanges || this.Any(a => a?.HasAnyChanges ?? false); - - public void BeginUpdate() - { - } - - public void CommitChanges() - { - HasChanges = false; - - foreach (var alertType in this) - { - alertType.CommitChanges(); - } - } - - public void EndUpdate() - { - } - - #region INotifyCollectionChanged - public event NotifyCollectionChangedEventHandler CollectionChanged; - #endregion - - protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) - { - CollectionChanged?.Invoke(this, e); - } - - public void NotifyAdd(AlertTypeValue item, bool setChanged = true) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); - if (setChanged) - HasChanges = true; - } - - public void NotifyClear(bool setChanged = true) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - if (setChanged) - HasChanges = true; - } - - public void NotifyRemove(AlertTypeValue item, int index, bool setChanged = true) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); - if (setChanged) - HasChanges = true; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/Bindable.cs b/Plugins/Discord/source/Plugin.Discord/Models/Bindable.cs deleted file mode 100644 index 8b12e9f4..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/Bindable.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.Serialization; - -namespace ServerManagerTool.Plugin.Discord -{ - [DataContract] - internal class Bindable : INotifyPropertyChanged, IBindable - { - private Dictionary _properties = new Dictionary(); - - protected bool _isUpdating = false; - - public Bindable() - { - _properties = new Dictionary(); - } - - protected T Get([CallerMemberName] string name = null) - { - object value = null; - if (_properties?.TryGetValue(name, out value) ?? false) - return value == null ? default(T) : (T)value; - return default(T); - } - - protected void Set(T value, bool setChanged = true, [CallerMemberName] string name = null) - { - if (Equals(value, Get(name))) - return; - if (_properties == null) - _properties = new Dictionary(); - _properties[name] = value; - OnPropertyChanged(name); - if (!_isUpdating && setChanged) - HasChanges = true; - } - - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - #region INotifyPropertyChanged - public event PropertyChangedEventHandler PropertyChanged; - #endregion - - #region IBindable - public bool HasChanges - { - get { return Get(); } - set { Set(value, false); } - } - - public virtual bool HasAnyChanges => HasChanges || (_properties?.Any(p => (p.Value as IBindable)?.HasAnyChanges ?? false) ?? false); - - public virtual void CommitChanges() - { - HasChanges = false; - - if (_properties == null) - return; - - foreach (var property in _properties) - { - var bindable = property.Value as IBindable; - if (bindable != null) - bindable.CommitChanges(); - } - } - - public void BeginUpdate() - { - _isUpdating = true; - } - - public void EndUpdate() - { - _isUpdating = false; - } - #endregion - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItem.cs b/Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItem.cs deleted file mode 100644 index 8cc71d5d..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItem.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Windows; - -namespace ServerManagerTool.Plugin.Discord -{ - public class ComboBoxItem : DependencyObject - { - public static readonly DependencyProperty ValueMemberProperty = DependencyProperty.Register(nameof(ValueMember), typeof(string), typeof(ComboBoxItem), new PropertyMetadata(string.Empty)); - public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register(nameof(DisplayMember), typeof(string), typeof(ComboBoxItem), new PropertyMetadata(string.Empty)); - public static readonly DependencyProperty GroupMemberProperty = DependencyProperty.Register(nameof(GroupMember), typeof(string), typeof(ComboBoxItem), new PropertyMetadata(string.Empty)); - - public ComboBoxItem() - { - } - - public ComboBoxItem(string valueMember, string displayMember) - { - ValueMember = valueMember; - DisplayMember = displayMember; - } - - public ComboBoxItem(string valueMember, string displayMember, string groupMember) - { - ValueMember = valueMember; - DisplayMember = displayMember; - GroupMember = groupMember; - } - - public string ValueMember - { - get { return (string)GetValue(ValueMemberProperty); } - set { SetValue(ValueMemberProperty, value); } - } - - public string DisplayMember - { - get { return (string)GetValue(DisplayMemberProperty); } - set { SetValue(DisplayMemberProperty, value); } - } - - public string GroupMember - { - get { return (string)GetValue(GroupMemberProperty); } - set { SetValue(GroupMemberProperty, value); } - } - - public ComboBoxItem Duplicate() - { - return new ComboBoxItem - { - DisplayMember = this.DisplayMember, - ValueMember = this.ValueMember, - GroupMember = this.GroupMember, - }; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItemList.cs b/Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItemList.cs deleted file mode 100644 index eb0c490c..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/ComboBoxItemList.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.ObjectModel; - -namespace ServerManagerTool.Plugin.Discord -{ - public class ComboBoxItemList : ObservableCollection - { - public ComboBoxItemList() - { - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/ConfigProfile.cs b/Plugins/Discord/source/Plugin.Discord/Models/ConfigProfile.cs deleted file mode 100644 index 2dfd109d..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/ConfigProfile.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System.Runtime.Serialization; - -namespace ServerManagerTool.Plugin.Discord -{ - [DataContract] - internal sealed class ConfigProfile : Bindable - { - public ConfigProfile() - : base() - { - Name = "New Discord Profile"; - ProfileNames = new ProfileNameValueList(); - AlertTypes = new AlertTypeValueList(); - DiscordWebhookUrl = string.Empty; - DiscordBotName = string.Empty; - DiscordUseTTS = false; - PrefixMessageWithProfileName = false; - MessageBold = false; - MessageUnderlined = false; - MessageItalic = false; - MessageCodeBlock = false; - IsEnabled = true; - } - - [DataMember] - public string Name - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public ProfileNameValueList ProfileNames - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public AlertTypeValueList AlertTypes - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public string DiscordWebhookUrl - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public string DiscordBotName - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool DiscordUseTTS - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool PrefixMessageWithProfileName - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool IsEnabled - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool MessageBold - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool MessageUnderlined - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool MessageItalic - { - get { return Get(); } - set { Set(value); } - } - - [DataMember] - public bool MessageCodeBlock - { - get { return Get(); } - set { Set(value); } - } - - public ConfigProfile Clone() - { - var clone = new ConfigProfile(); - clone.Name = this.Name; - - foreach (var profileName in this.ProfileNames) - { - clone.ProfileNames.Add(new ProfileNameValue(profileName.Value, profileName.OriginalValue) { HasChanges = profileName.HasChanges }); - } - clone.ProfileNames.HasChanges = this.ProfileNames.HasChanges; - foreach (var alertType in this.AlertTypes) - { - clone.AlertTypes.Add(new AlertTypeValue(alertType.Value, alertType.OriginalValue) { HasChanges = alertType.HasChanges }); - } - clone.AlertTypes.HasChanges = this.AlertTypes.HasChanges; - - clone.DiscordWebhookUrl = this.DiscordWebhookUrl; - clone.DiscordBotName = this.DiscordBotName; - clone.DiscordUseTTS = this.DiscordUseTTS; - clone.PrefixMessageWithProfileName = this.PrefixMessageWithProfileName; - clone.MessageBold = this.MessageBold; - clone.MessageUnderlined = this.MessageUnderlined; - clone.MessageItalic = this.MessageItalic; - clone.MessageCodeBlock = this.MessageCodeBlock; - clone.IsEnabled = this.IsEnabled; - clone.HasChanges = this.HasChanges; - return clone; - } - - public void CopyFrom(ConfigProfile source) - { - if (source == null) - return; - - try - { - this.BeginUpdate(); - - this.Name = source.Name; - - this.ProfileNames.BeginUpdate(); - this.ProfileNames.Clear(); - foreach (var profileName in source.ProfileNames) - { - this.ProfileNames.Add(new ProfileNameValue(profileName.Value, profileName.OriginalValue)); - } - if (source.ProfileNames.HasChanges) - this.ProfileNames.HasChanges = true; - this.ProfileNames.EndUpdate(); - - this.AlertTypes.BeginUpdate(); - this.AlertTypes.Clear(); - foreach (var alertType in source.AlertTypes) - { - this.AlertTypes.Add(new AlertTypeValue(alertType.Value, alertType.OriginalValue)); - } - if (source.AlertTypes.HasChanges) - this.AlertTypes.HasChanges = true; - this.AlertTypes.EndUpdate(); - - this.DiscordWebhookUrl = source.DiscordWebhookUrl; - this.DiscordBotName = source.DiscordBotName; - this.DiscordUseTTS = source.DiscordUseTTS; - this.PrefixMessageWithProfileName = source.PrefixMessageWithProfileName; - this.MessageBold = source.MessageBold; - this.MessageUnderlined = source.MessageUnderlined; - this.MessageItalic = source.MessageItalic; - this.MessageCodeBlock = source.MessageCodeBlock; - this.IsEnabled = source.IsEnabled; - - if (source.HasChanges) - this.HasChanges = true; - } - finally - { - this.EndUpdate(); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/DiscordPluginConfig.cs b/Plugins/Discord/source/Plugin.Discord/Models/DiscordPluginConfig.cs deleted file mode 100644 index b0705f91..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/DiscordPluginConfig.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace ServerManagerTool.Plugin.Discord -{ - [DataContract] - internal sealed class DiscordPluginConfig : Bindable - { - public DiscordPluginConfig() - : base() - { - LastCallHome = DateTime.MinValue; - ConfigProfiles = new ObservableList(); - } - - [DataMember] - public DateTime LastCallHome - { - get; - set; - } - - [DataMember] - public ObservableList ConfigProfiles - { - get { return Get>(); } - set { Set(value); } - } - - public override bool HasAnyChanges - { - get => base.HasChanges || (ConfigProfiles?.HasAnyChanges ?? false); - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/ObservableList.cs b/Plugins/Discord/source/Plugin.Discord/Models/ObservableList.cs deleted file mode 100644 index 6f7e922b..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/ObservableList.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Runtime.Serialization; - -namespace ServerManagerTool.Plugin.Discord -{ - [DataContract] - internal class ObservableList : Bindable, IList, INotifyCollectionChanged - { - private List _listObject = null; - - public ObservableList() - : base() - { - _listObject = new List(); - CommitChanges(); - } - - public override bool HasAnyChanges => base.HasChanges || (_listObject?.Any(i => (i as IBindable)?.HasAnyChanges ?? false) ?? false); - - public override void CommitChanges() - { - base.CommitChanges(); - - if (_listObject == null) - return; - - foreach (T item in _listObject) - { - var bindable = item as IBindable; - if (bindable != null) - bindable.CommitChanges(); - } - } - - [DataMember] - internal List List - { - get => _listObject; - set => _listObject = value; - } - - #region IList - public T this[int index] - { - get => _listObject[index]; - set - { - T oldValue = _listObject[index]; - _listObject[index] = value; - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue)); - } - } - - public int Count => _listObject.Count; - - public bool IsReadOnly => false; - - public void Add(T item) - { - _listObject.Add(item); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); - } - - public void Clear() - { - _listObject.Clear(); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - - public bool Contains(T item) - { - return _listObject.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _listObject.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return _listObject.GetEnumerator(); - } - - public int IndexOf(T item) - { - return _listObject.IndexOf(item); - } - - public void Insert(int index, T item) - { - _listObject.Insert(index, item); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); - } - - public void Move(int oldIndex, int newIndex) - { - var item = _listObject.ElementAt(oldIndex); - if (item != null) - { - _listObject.Remove(item); - _listObject.Insert(newIndex, item); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, item, newIndex, oldIndex)); - } - } - - public bool Remove(T item) - { - int index = _listObject.IndexOf(item); - var result = _listObject.Remove(item); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); - return result; - } - - public void RemoveAt(int index) - { - T item = _listObject[index]; - _listObject.RemoveAt(index); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _listObject.GetEnumerator(); - } - #endregion - - #region INotifyCollectionChanged - public event NotifyCollectionChangedEventHandler CollectionChanged; - - protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) - { - CollectionChanged?.Invoke(this, e); - if (!_isUpdating) - HasChanges = true; - } - #endregion - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValue.cs b/Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValue.cs deleted file mode 100644 index e505f555..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValue.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Runtime.Serialization; - -namespace ServerManagerTool.Plugin.Discord -{ - [DataContract] - internal class ProfileNameValue : Bindable - { - public ProfileNameValue() - : base() - { - Value = string.Empty; - OriginalValue = Value; - HasChanges = false; - } - - public ProfileNameValue(string value) - : base() - { - Value = value; - OriginalValue = Value; - HasChanges = !Value.Equals(OriginalValue); - } - - public ProfileNameValue(string value, string originalValue) - : base() - { - Value = value; - OriginalValue = originalValue; - HasChanges = !Value.Equals(OriginalValue); - } - - [DataMember] - public string Value - { - get { return Get(); } - set { Set(value); } - } - - public string OriginalValue - { - get; - set; - } - - public override bool HasAnyChanges => base.HasChanges && !Value.Equals(OriginalValue); - - public override void CommitChanges() - { - base.CommitChanges(); - - OriginalValue = Value; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValueList.cs b/Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValueList.cs deleted file mode 100644 index 9101cabb..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/ProfileNameValueList.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; - -namespace ServerManagerTool.Plugin.Discord -{ - internal class ProfileNameValueList : List, IBindable, INotifyCollectionChanged - { - private bool _hasChanges = false; - - public bool HasChanges - { - get => _hasChanges; - set => _hasChanges = value; - } - - public bool HasAnyChanges => _hasChanges || this.Any(p => p?.HasAnyChanges ?? false); - - public void BeginUpdate() - { - } - - public void CommitChanges() - { - HasChanges = false; - - foreach (var profileName in this) - { - profileName.CommitChanges(); - } - } - - public void EndUpdate() - { - } - - #region INotifyCollectionChanged - public event NotifyCollectionChangedEventHandler CollectionChanged; - #endregion - - protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) - { - CollectionChanged?.Invoke(this, e); - } - - public void NotifyAdd(ProfileNameValue item, bool setChanged = true) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); - if (setChanged) - HasChanges = true; - } - - public void NotifyClear(bool setChanged = true) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - if (setChanged) - HasChanges = true; - } - - public void NotifyRemove(ProfileNameValue item, int index, bool setChanged = true) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); - if (setChanged) - HasChanges = true; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/VersionFeed.cs b/Plugins/Discord/source/Plugin.Discord/Models/VersionFeed.cs deleted file mode 100644 index db41f723..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/VersionFeed.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ServerManagerTool.Plugin.Discord -{ - public class VersionFeed - { - public string Id { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public string SubTitle { get; set; } = string.Empty; - public Uri Link { get; set; } = null; - public DateTimeOffset Updated { get; set; } = DateTimeOffset.Now; - - public List Entries { get; set; } = new List(); - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Models/VersionFeedEntry.cs b/Plugins/Discord/source/Plugin.Discord/Models/VersionFeedEntry.cs deleted file mode 100644 index 6883a4fd..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Models/VersionFeedEntry.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace ServerManagerTool.Plugin.Discord -{ - public class VersionFeedEntry - { - public string Id { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public string Summary { get; set; } = string.Empty; - public Uri Link { get; set; } = null; - public DateTimeOffset Updated { get; set; } = DateTimeOffset.Now; - public string Content { get; set; } = string.Empty; - public string Author { get; set; } = string.Empty; - - public bool IsCurrent { get; set; } = false; - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Plugin.Discord.csproj b/Plugins/Discord/source/Plugin.Discord/Plugin.Discord.csproj deleted file mode 100644 index 72a4460e..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Plugin.Discord.csproj +++ /dev/null @@ -1,75 +0,0 @@ - - - %24/Development/ServerManagers/Main/Plugin.Discord - {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} - https://dev.azure.com/bretthewitson - . - - - net462 - false - Art\favicon.ico - ServerManager.Plugin.Discord - ServerManagerTool.Plugin.Discord - - - none - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Config.settings - - - - - SettingsSingleFileGenerator - Config.Designer.cs - - - \ No newline at end of file diff --git a/Plugins/Discord/source/Plugin.Discord/Properties/AssemblyInfo.cs b/Plugins/Discord/source/Plugin.Discord/Properties/AssemblyInfo.cs deleted file mode 100644 index d7975adb..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServerManager Discord Plugin")] -[assembly: AssemblyDescription("A Discord plugin that can be used with the server managers.")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Bletch1971")] -[assembly: AssemblyProduct("Server Managers")] -[assembly: AssemblyCopyright("Copyright © 2015-2020")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("936ef260-fecf-4e9e-a21e-092d65931c7d")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.17.2")] -[assembly: AssemblyFileVersion("1.0.17.2")] diff --git a/Plugins/Discord/source/Plugin.Discord/Utils/NetworkUtils.cs b/Plugins/Discord/source/Plugin.Discord/Utils/NetworkUtils.cs deleted file mode 100644 index 0590e7d4..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Utils/NetworkUtils.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Threading.Tasks; - -namespace ServerManagerTool.Plugin.Discord -{ - internal static class NetworkUtils - { - public static async Task DiscoverPublicIPAsync() - { - using (var webClient = new WebClient()) - { - try - { - var publicIP = await webClient.DownloadStringTaskAsync(Config.Default.PublicIPCheckUrl); - - if (IPAddress.TryParse(publicIP, out IPAddress address)) - return address; - - return IPAddress.None; - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(DiscoverPublicIPAsync)}\r\n{ex.Message}"); - return IPAddress.None; - } - } - } - - public static async Task CheckLatestVersionAsync(bool betaEnabled) - { - try - { - using (var webClient = new WebClient()) - { - string latestVersion = null; - - if (betaEnabled) - latestVersion = await webClient.DownloadStringTaskAsync(Config.Default.LatestBetaVersionUrl); - else - latestVersion = await webClient.DownloadStringTaskAsync(Config.Default.LatestVersionUrl); - - if (Version.TryParse(latestVersion, out Version version)) - return version; - - return new Version(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(CheckLatestVersionAsync)}\r\n{ex.Message}"); - return new Version(); - } - } - - public static bool DownloadLatestVersion(string sourceUrl, string destinationFile) - { - try - { - using (var client = new WebClient()) - { - client.DownloadFile(sourceUrl, destinationFile); - return true; - } - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(DownloadLatestVersion)}\r\n{ex.Message}"); - return false; - } - } - - public static async Task PerformCallToAPIAsync(string pluginCode, IPAddress ipAddress) - { - try - { - using (var client = new WebClient()) - { - var url = string.Format(Config.Default.PluginCallUrlFormat, pluginCode, ipAddress); - await client.DownloadStringTaskAsync(url); - } - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(PerformCallToAPIAsync)} - {pluginCode}; {ipAddress}\r\n{ex.Message}"); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Utils/TaskUtils.cs b/Plugins/Discord/source/Plugin.Discord/Utils/TaskUtils.cs deleted file mode 100644 index 52439873..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Utils/TaskUtils.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace ServerManagerTool.Plugin.Discord -{ - internal static class TaskUtils - { - public static readonly Task FinishedTask = Task.FromResult(true); - - public static void DoNotWait(this Task task) - { - // Do nothing, let the task continue. Eliminates compiler warning about non-awaited tasks in an async method. - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Utils/VersionFeedUtils.cs b/Plugins/Discord/source/Plugin.Discord/Utils/VersionFeedUtils.cs deleted file mode 100644 index 3059e059..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Utils/VersionFeedUtils.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.ServiceModel.Syndication; -using System.Xml; - -namespace ServerManagerTool.Plugin.Discord -{ - public static class VersionFeedUtils - { - public static VersionFeed LoadVersionFeed(string inputUri, string currentVersion) - { - try - { - var reader = XmlReader.Create(inputUri); - var feed = SyndicationFeed.Load(reader); - - var versionFeed = new VersionFeed - { - Id = feed.Id, - Title = feed.Title?.Text, - SubTitle = feed.Description?.Text, - Link = feed.Links?[0].Uri, - Updated = feed.LastUpdatedTime.ToLocalTime(), - }; - - //Loop through all items in the SyndicationFeed - foreach (var item in feed.Items) - { - var textContent = item.Content as TextSyndicationContent; - - var versionFeedEntry = new VersionFeedEntry - { - Id = item.Id, - Title = item.Title?.Text, - Summary = item.Summary?.Text, - Link = item.Links?[0].Uri, - Updated = item.LastUpdatedTime.ToLocalTime(), - Content = textContent?.Text, - Author = item.Authors?[0].Name, - - IsCurrent = (item.Summary?.Text ?? string.Empty).Equals(currentVersion), - }; - versionFeed.Entries.Add(versionFeedEntry); - } - - return versionFeed; - } - catch (Exception) - { - return new VersionFeed(); - } - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Utils/WindowUtils.cs b/Plugins/Discord/source/Plugin.Discord/Utils/WindowUtils.cs deleted file mode 100644 index 6c765945..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Utils/WindowUtils.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Media; - -namespace ServerManagerTool.Plugin.Discord -{ - public static class WindowUtils - { - public static void RemoveDefaultResourceDictionary(Window window, string defaultDictionary) - { - if (window == null) - return; - - var dictToRemove = window.Resources.MergedDictionaries.FirstOrDefault(d => d.Source.OriginalString.Contains(defaultDictionary)); - if (dictToRemove != null) - { - window.Resources.MergedDictionaries.Remove(dictToRemove); - } - } - - public static void RemoveDefaultResourceDictionary(UserControl control, string defaultDictionary) - { - if (control == null) - return; - - var dictToRemove = control.Resources.MergedDictionaries.FirstOrDefault(d => d.Source.OriginalString.Contains(defaultDictionary)); - if (dictToRemove != null) - { - control.Resources.MergedDictionaries.Remove(dictToRemove); - } - } - - /// - /// Finds a parent of a given item on the visual tree. - /// - /// The type of the queried item. - /// A direct or indirect child of the queried item. - /// The first parent item that matches the submitted type parameter. If not matching item can be found, a null reference is being returned. - public static T TryFindParent(DependencyObject child) - where T : DependencyObject - { - //get parent item - DependencyObject parentObject = GetParentObject(child); - - //we've reached the end of the tree - if (parentObject == null) return null; - - //check if the parent matches the type we're looking for - T parent = parentObject as T; - if (parent != null) - return parent; - - //use recursion to proceed with next level - return TryFindParent(parentObject); - } - - /// - /// This method is an alternative to WPF's method, which also supports content elements. - /// Do note, that for content element, this method falls back to the logical tree of the element. - /// - /// The item to be processed. - /// The submitted item's parent, if available. Otherwise null. - public static DependencyObject GetParentObject(DependencyObject child) - { - if (child == null) return null; - var contentElement = child as ContentElement; - - if (contentElement != null) - { - var parent = ContentOperations.GetParent(contentElement); - if (parent != null) return parent; - - var fce = contentElement as FrameworkContentElement; - return fce?.Parent; - } - - //if it's not a ContentElement, rely on VisualTreeHelper - return VisualTreeHelper.GetParent(child); - } - - /// - /// Recursively processes a given dependency object and all its children, and updates sources of all objects that use a binding expression on a given property. - /// - /// The dependency object that marks a starting point. This could be a dialog window or a panel control that hosts bound controls. - /// The properties to be updated if - /// or one of its childs provide it along with a binding expression. - public static void UpdateBindingSources(DependencyObject obj, params DependencyProperty[] properties) - { - foreach (var depProperty in properties) - { - //check whether the submitted object provides a bound property that matches the property parameters - var be = BindingOperations.GetBindingExpression(obj, depProperty); - be?.UpdateSource(); - } - - int count = VisualTreeHelper.GetChildrenCount(obj); - for (int i = 0; i < count; i++) - { - //process child items recursively - var childObject = VisualTreeHelper.GetChild(obj, i); - UpdateBindingSources(childObject, properties); - } - } - - /// - /// Tries to locate a given item within the visual tree, starting with the dependency object at a given position. - /// - /// The type of the element to be found on the visual tree of the element at the given location. - /// The main element which is used to perform hit testing. - /// The position to be evaluated on the origin. - public static T TryFindFromPoint(UIElement reference, Point point) - where T : DependencyObject - { - var element = reference.InputHitTest(point) as DependencyObject; - if (element == null) return null; - if (element is T) return (T)element; - return TryFindParent(element); - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/VersionFeed.xml b/Plugins/Discord/source/Plugin.Discord/VersionFeed.xml deleted file mode 100644 index 82e77d98..00000000 --- a/Plugins/Discord/source/Plugin.Discord/VersionFeed.xml +++ /dev/null @@ -1,316 +0,0 @@ - - - - urn:uuid:C93B24FC-C8DB-44F3-8B6F-A27A52E7AF9F - Discord Plugin Version Feed - This is the Discord Plugin release version feed. - - 2020-07-13T00:00:00Z - - - urn:uuid:D8974ABF-8444-4D40-A594-D4443921B3B8 - 1.0.17 (1.0.17.2) - 1.0.17.2 - - 2020-07-13T00:00:00Z - -
-

- CHANGE -
-

    -
  • Profile name has been converted to a droplist and is now populated with the Server Manager Profile Names for selection.
  • -
  • Added drag/drop feature to the config window.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:A7158CB1-C5B2-4505-B171-CDD54918B227 - 1.0.16 (1.0.16.1) - 1.0.16.1 - - 2020-06-12T00:00:01Z - -
-

- BUGFIX -
-

    -
  • Added url encoding so that special characters are sent to the webhook correctly.
  • -
  • Changed the text encoding from ASCII to UTF8, so that unicode languages should work correctly.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:6ADCC571-3933-44E1-91FB-4DC8F8B836F2 - 1.0.15 (1.0.15.1) - 1.0.15.1 - - 2020-03-03T00:00:01Z - -
-

- CHANGE -
-

    -
  • Config Save - nows creates a backup file (.bak) of the config file before the new changes are saved.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:6ADCC571-3933-44E1-91FB-4DC8F8B836F2 - 1.0.14 (1.0.14.2) - 1.0.14.2 - - 2018-08-16T00:00:01Z - -
-

- CHANGE -
-

    -
  • Download Location Changed - Have moved the server manager files to a new location for hosting.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:6ADCC571-3933-44E1-91FB-4DC8F8B836F2 - 1.0.13 (1.0.13.1) - 1.0.13.1 - - 2018-06-13T04:40:00Z - -
-

- NEW -
-

    -
  • Message Options - Added new message options to display the messages in Bold, Italic, Underlined and Embedded Code Block.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:21C68E55-E915-4337-8CFB-7E96FE6967CB - 1.0.12 (1.0.12.1) - 1.0.12.1 - - 2018-05-24T00:20:00Z - -
-

- NEW -
-

    -
  • Added version feed window.
  • -
- CHANGE -
-
    -
  • DotNet Framework updated.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:C1ED0129-58CF-4AA4-8203-DDFA199E17DE - 1.0.11 (1.0.11.0) - 1.0.11.0 - - 2018-05-24T00:20:00Z - -
-

- CHANGE -
-

    -
  • Icons - all icons have be cleaned up and updated.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:58894ADA-FDC4-4F5A-A904-B81D9130FD00 - 1.0.10 (1.0.10.0) - 1.0.10.0 - - 2018-05-24T00:20:00Z - -
-

- BUGFIX -
-

    -
  • Attempt to fix the save config bug, where the config file is blank.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:20DB658C-44FA-4642-923B-A94926B0FDC3 - 1.0.9 (1.0.9.0) - 1.0.9.0 - - 2018-05-24T00:20:00Z - -
-

- BUGFIX -
-

    -
  • Some minor bugfixes and code cleanup.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:3B0D107D-77DB-4E70-BE8A-336A20A55F8A - 1.0.8 (1.0.8.0) - 1.0.8.0 - - 2018-05-24T00:20:00Z - -
-

- CHANGE -
-

    -
  • Changed the download location of the plugin.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:CDA4857D-FC4A-44AB-A11E-9CC1CDA11BCD - 1.0.7 (1.0.7.0) - 1.0.7.0 - - 2018-05-24T00:20:00Z - -
-

- CHANGE -
-

    -
  • Minor code clean-up and tweaks.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:C6CEC6B2-E405-4DF6-B991-FC1D4EEDF3E8 - 1.0.6 (1.0.6.0) - 1.0.6.0 - - 2018-05-24T00:20:00Z - -
-

- CHANGE -
-

    -
  • Have changed the storage host for the discord plugin.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:9C4A9557-3A74-428F-A22C-727CBBFB6E91 - 1.0.5 (1.0.5.0) - 1.0.5.0 - - 2018-05-24T00:20:00Z - -
-

- NEW -
-

    -
  • New discord plugin to send Server Manager alerts to one or more channels on your discord server.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- -
\ No newline at end of file diff --git a/Plugins/Discord/source/Plugin.Discord/VersionFeedBeta.xml b/Plugins/Discord/source/Plugin.Discord/VersionFeedBeta.xml deleted file mode 100644 index de95f6f5..00000000 --- a/Plugins/Discord/source/Plugin.Discord/VersionFeedBeta.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - urn:uuid:6BB39661-8638-425E-B5F7-0C75AACC1D26 - Discord Plugin Version Feed - This is the Discord Plugin beta version feed. - - 2020-07-12T02:00:00Z - - - urn:uuid:4750D17C-2C8F-4D8C-AA17-B3512F002170 - 1.0.17 (1.0.17.2) - 1.0.17.2 - - 2020-07-12T02:00:00Z - -
-

- CHANGE -
-

    -
  • Added drag/drop feature to the config window.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- - - urn:uuid:D8974ABF-8444-4D40-A594-D4443921B3B8 - 1.0.17 (1.0.17.1) - 1.0.17.1 - - 2020-07-12T00:00:00Z - -
-

- CHANGE -
-

    -
  • Profile name has been converted to a droplist and is now populated with the Server Manager Profile Names for selection.
  • -
-

-
-
- - bletch - bletch1971@hotmail.com - -
- -
\ No newline at end of file diff --git a/Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml b/Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml deleted file mode 100644 index d1ce9835..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml.cs b/Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml.cs deleted file mode 100644 index 1a9d84da..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Windows/ConfigProfileWindow.xaml.cs +++ /dev/null @@ -1,320 +0,0 @@ -using ServerManagerTool.Plugin.Common; -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; - -namespace ServerManagerTool.Plugin.Discord.Windows -{ - /// - /// Interaction logic for ConfigProfileWindow.xaml - /// - public partial class ConfigProfileWindow : Window - { - private static readonly DependencyProperty ProfileProperty = DependencyProperty.Register(nameof(Profile), typeof(ConfigProfile), typeof(ConfigProfileWindow)); - private static readonly DependencyProperty ProfileListProperty = DependencyProperty.Register(nameof(ProfileList), typeof(ComboBoxItemList), typeof(ConfigProfileWindow)); - - internal ConfigProfileWindow(DiscordPlugin plugin, ConfigProfile profile) - { - this.Plugin = plugin ?? new DiscordPlugin(); - this.OriginalProfile = profile; - this.Profile = profile.Clone(); - this.Profile.CommitChanges(); - - RefreshProfileList(); - - InitializeComponent(); - - if (plugin.BetaEnabled) - Title = $"{Title} {ResourceUtils.GetResourceString(this.Resources, "Global_BetaModeLabel")}"; - - this.DataContext = this; - } - - private ConfigProfile OriginalProfile - { - get; - set; - } - - private ConfigProfile Profile - { - get { return GetValue(ProfileProperty) as ConfigProfile; } - set { SetValue(ProfileProperty, value); } - } - - private DiscordPlugin Plugin - { - get; - set; - } - - private ComboBoxItemList ProfileList - { - get { return GetValue(ProfileListProperty) as ComboBoxItemList; } - set { SetValue(ProfileListProperty, value); } - } - - private void ConfigProfileWindow_Closing(object sender, CancelEventArgs e) - { - if (DialogResult.HasValue && DialogResult.Value) - return; - - if (this.Profile.HasAnyChanges) - { - if (MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_CloseLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_CloseTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) - e.Cancel = true; - } - } - - private void ComboBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e) - { - var comboBox = sender as ComboBox; - if (comboBox == null) - return; - - if (comboBox.IsDropDownOpen) - return; - - e.Handled = true; - } - - private void Ok_Click(object sender, RoutedEventArgs e) - { - if (this.Profile.HasAnyChanges) - { - this.OriginalProfile.CopyFrom(this.Profile); - } - - DialogResult = true; - Close(); - } - - private void Test_Click(object sender, RoutedEventArgs e) - { - if (!Profile.IsEnabled) - { - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_TestEnabledErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_TestErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - - try - { - foreach (var profileName in Profile.ProfileNames) - { - foreach (var alertType in Profile.AlertTypes) - { - Plugin.HandleAlert(Profile, alertType.Value, profileName.Value, $"Test '{alertType.Value}' message for profile name '{profileName.Value}'."); - Task.Delay(1000).Wait(); - } - } - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(Test_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_TestErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_TestErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void AddAlertType_Click(object sender, RoutedEventArgs e) - { - try - { - var alertType = new AlertTypeValue(AlertType.Error); - - Profile.AlertTypes.Add(alertType); - Profile.AlertTypes.NotifyAdd(alertType); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(AddAlertType_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_AddAlertTypeErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_AddErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void ClearAlertTypes_Click(object sender, RoutedEventArgs e) - { - if (MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) - return; - - try - { - if (Profile.AlertTypes.Count == 0) - return; - - Profile.AlertTypes.Clear(); - Profile.AlertTypes.NotifyClear(); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(ClearAlertTypes_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearAlertTypesErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void DeleteAlertType_Click(object sender, RoutedEventArgs e) - { - if (MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) - return; - - try - { - var alertType = ((AlertTypeValue)((Button)e.Source).DataContext); - var index = Profile.AlertTypes.IndexOf(alertType); - Profile.AlertTypes.Remove(alertType); - Profile.AlertTypes.NotifyRemove(alertType, index); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(DeleteAlertType_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteAlertTypeErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void AddProfileName_Click(object sender, RoutedEventArgs e) - { - try - { - var profileName = new ProfileNameValue(); - - Profile.ProfileNames.Add(profileName); - Profile.ProfileNames.NotifyAdd(profileName); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(AddProfileName_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_AddProfileNameErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_AddErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void ClearProfileNames_Click(object sender, RoutedEventArgs e) - { - if (MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) - return; - - try - { - if (Profile.ProfileNames.Count == 0) - return; - - Profile.ProfileNames.Clear(); - Profile.ProfileNames.NotifyClear(); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(ClearProfileNames_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearProfileNamesErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_ClearErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void DeleteProfileName_Click(object sender, RoutedEventArgs e) - { - if (MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) - return; - - try - { - var profileName = ((ProfileNameValue)((Button)e.Source).DataContext); - var index = Profile.ProfileNames.IndexOf(profileName); - Profile.ProfileNames.Remove(profileName); - Profile.ProfileNames.NotifyRemove(profileName, index); - } - catch (Exception ex) - { - Debug.WriteLine($"ERROR: {nameof(DeleteProfileName_Click)}\r\n{ex.Message}"); - MessageBox.Show(ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteProfileNameErrorLabel"), ResourceUtils.GetResourceString(this.Resources, "ConfigProfileWindow_DeleteErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - private void ComboBox_GotFocus(object sender, RoutedEventArgs e) - { - var comboBox = sender as ComboBox; - if (comboBox == null) - return; - - try - { - comboBox.BeginInit(); - } - finally - { - comboBox.EndInit(); - } - } - - private void ComboBox_LostFocus(object sender, RoutedEventArgs e) - { - var comboBox = sender as ComboBox; - if (comboBox == null) - return; - - if (comboBox.SelectedItem == null) - { - var text = comboBox.Text; - - if (!string.IsNullOrWhiteSpace(text)) - { - var source = comboBox.ItemsSource as ComboBoxItemList; - source?.Add(new ComboBoxItem - { - ValueMember = text, - DisplayMember = text, - }); - } - - comboBox.SelectedValue = text; - } - - var expression = comboBox.GetBindingExpression(Selector.SelectedValueProperty); - expression?.UpdateSource(); - - expression = comboBox.GetBindingExpression(ComboBox.TextProperty); - expression?.UpdateSource(); - } - - private void RefreshProfileList() - { - var newList = new ComboBoxItemList(); - newList.Add(new ComboBoxItem - { - ValueMember = string.Empty, - DisplayMember = string.Empty, - }); - - try - { - foreach (var profile in PluginHelper.Instance.FetchProfileList()) - { - newList.Add(new ComboBoxItem - { - ValueMember = profile.ProfileName, - DisplayMember = $"* {profile.ProfileName}", - }); - } - } - catch - { - // do nothing, most likely they are using an older version of a server manager - } - - foreach (var profile in Profile.ProfileNames) - { - if (!newList.Any(p => p.ValueMember.Equals(profile.Value, StringComparison.OrdinalIgnoreCase))) - { - newList.Add(new ComboBoxItem - { - ValueMember = profile.Value, - DisplayMember = profile.Value, - }); - } - } - - this.ProfileList = newList; - } - } -} diff --git a/Plugins/Discord/source/Plugin.Discord/Windows/ConfigWindow.xaml b/Plugins/Discord/source/Plugin.Discord/Windows/ConfigWindow.xaml deleted file mode 100644 index a2eb74c0..00000000 --- a/Plugins/Discord/source/Plugin.Discord/Windows/ConfigWindow.xaml +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -