diff --git a/.gitignore b/.gitignore index a9cf1744..d73a9caa 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ TestStore/ /Plugin.pdb deploy/** *.ffplugin +DiscordNodes/settings.json diff --git a/BasicNodes/BasicNodes.csproj b/BasicNodes/BasicNodes.csproj index ae5f80ec..d9b0bb7e 100644 Binary files a/BasicNodes/BasicNodes.csproj and b/BasicNodes/BasicNodes.csproj differ diff --git a/ChecksumNodes/ChecksumNodes.csproj b/ChecksumNodes/ChecksumNodes.csproj index a4dacc78..45ab0a6c 100644 Binary files a/ChecksumNodes/ChecksumNodes.csproj and b/ChecksumNodes/ChecksumNodes.csproj differ diff --git a/CollectionNodes/CollectionNodes.csproj b/CollectionNodes/CollectionNodes.csproj index d1b7f0c1..33395a2d 100644 Binary files a/CollectionNodes/CollectionNodes.csproj and b/CollectionNodes/CollectionNodes.csproj differ diff --git a/DiscordNodes/Communication/Discord.cs b/DiscordNodes/Communication/Discord.cs new file mode 100644 index 00000000..7b59b73f --- /dev/null +++ b/DiscordNodes/Communication/Discord.cs @@ -0,0 +1,123 @@ +using System.ComponentModel; +using System.Text.Json; + +namespace FileFlows.DiscordNodes.Communication; + +public class Discord: Node +{ + public override int Inputs => 1; + public override int Outputs => 2; + public override FlowElementType Type => FlowElementType.Process; + public override string Icon => "fab fa-discord"; + + [Required] + [TextVariable(1)] + public string Message { get; set; } + + [TextVariable(2)] + public string Title { get; set; } + + [DefaultValue("standard")] + [Select(nameof(MessageTypeOptions), 3)] + public string MessageType { get; set; } + + private static List _MessageTypeOptions; + public static List MessageTypeOptions + { + get + { + if (_MessageTypeOptions == null) + { + _MessageTypeOptions = new List + { + new ListOption { Label = "Information", Value = "Information"}, + new ListOption { Label = "Success", Value = "Success"}, + new ListOption { Label = "Warning", Value = "Warning" }, + new ListOption { Label = "Error", Value = "Error"}, + new ListOption { Label = "Failure", Value = "Failure"}, + new ListOption { Label = "Basic", Value = "Basic"}, + }; + } + return _MessageTypeOptions; + } + } + + const int colorInfo = 0x1F61E6; + const int colorSuccess= 0x80E61F; + const int colorError = 0xE7421F; + const int colorFailure = 0xC61FE6; + const int colorWarning = 0xE6C71F; + + public override int Execute(NodeParameters args) + { + var settings = args.GetPluginSettings(); + + if (string.IsNullOrWhiteSpace(settings?.WebhookId)) + { + args.Logger?.WLog("No webhook id set"); + return 2; + } + if (string.IsNullOrWhiteSpace(settings?.WebhookToken)) + { + args.Logger?.WLog("No webhook token set"); + return 2; + } + + string message = args.ReplaceVariables(this.Message); + if (string.IsNullOrWhiteSpace(message)) + { + args.Logger?.WLog("No message to send"); + return 2; + } + string title = args.ReplaceVariables(this.Title)?.EmptyAsNull() ?? this.MessageType?.EmptyAsNull() ?? "Information"; + + object webhook; + if (this.MessageType == "Basic") + { + webhook = new + { + username = "FileFlows", + content = message, + avatar_url = "https://fileflows.com/icon.png", + }; + + } + else + { + webhook = new + { + username = "FileFlows", + avatar_url = "https://fileflows.com/icon.png", + embeds = new[] + { + new { + description = message, + title = title, + color = this.MessageType switch + { + "Success" => colorSuccess, + "Warning" => colorWarning, + "Error" => colorError, + "Failure" => colorFailure, + _ => colorInfo, + } + } + } + }; + } + + + string url = $"https://discordapp.com/api/webhooks/{settings.WebhookId}/{settings.WebhookToken}"; + + var content = new StringContent(JsonSerializer.Serialize(webhook), Encoding.UTF8, "application/json"); + + using var httpClient = new HttpClient(); + var response = httpClient.PostAsync(url, content).Result; + if (response.IsSuccessStatusCode) + return 1; + + string error = response.Content.ReadAsStringAsync().Result; + args.Logger?.WLog("Error from discord: " + error); + return 2; + } +} diff --git a/DiscordNodes/DiscordNodes.csproj b/DiscordNodes/DiscordNodes.csproj new file mode 100644 index 00000000..6f3d9c5b Binary files /dev/null and b/DiscordNodes/DiscordNodes.csproj differ diff --git a/DiscordNodes/DiscordNodes.en.json b/DiscordNodes/DiscordNodes.en.json new file mode 100644 index 00000000..1f750781 --- /dev/null +++ b/DiscordNodes/DiscordNodes.en.json @@ -0,0 +1,30 @@ +{ + "Plugins": { + "DiscordNodes": { + "Description": "A plugin that allows you to send messages to a Discord server.\n\nThe Webhook Id and token can be obtained from the webhook URL\n https://discord.com/api/webhooks/[webhookid]/[webhooktoken]", + "Fields": { + "WebhookId": "Webhook Id", + "WebhookToken": "Webhook Token" + } + } + }, + "Flow": { + "Parts": { + "Discord": { + "Outputs": { + "1": "Discord message sent", + "2": "Discord message failed to send" + }, + "Description": "Sends a message to a Discord server.", + "Fields": { + "Message": "Message", + "Message-Help": "The message to send to the Discord server", + "Title": "Title", + "Title-Help": "An optional title to send, if not set the message type will be the title.", + "MessageType": "Type", + "MessageType-Help": "The type of message to send. Basic type will be just the message without a title and no colouring." + } + } + } + } +} \ No newline at end of file diff --git a/DiscordNodes/ExtensionMethods.cs b/DiscordNodes/ExtensionMethods.cs new file mode 100644 index 00000000..8a814624 --- /dev/null +++ b/DiscordNodes/ExtensionMethods.cs @@ -0,0 +1,6 @@ +namespace FileFlows.DiscordNodes; + +internal static class ExtensionMethods +{ + public static string? EmptyAsNull(this string str) => str == string.Empty ? null : str; +} diff --git a/DiscordNodes/GlobalUsings.cs b/DiscordNodes/GlobalUsings.cs new file mode 100644 index 00000000..2d96a460 --- /dev/null +++ b/DiscordNodes/GlobalUsings.cs @@ -0,0 +1,8 @@ +global using System; +global using System.Collections.Generic; +global using System.Linq; +global using System.Text; +global using System.Threading.Tasks; +global using System.ComponentModel.DataAnnotations; +global using FileFlows.Plugin; +global using FileFlows.Plugin.Attributes; \ No newline at end of file diff --git a/DiscordNodes/Plugin.cs b/DiscordNodes/Plugin.cs new file mode 100644 index 00000000..fa1cf0f7 --- /dev/null +++ b/DiscordNodes/Plugin.cs @@ -0,0 +1,11 @@ +namespace FileFlows.DiscordNodes; + +public class Plugin : FileFlows.Plugin.IPlugin +{ + public string Name => "Discord Nodes"; + public string MinimumVersion => "0.5.0.683"; + + public void Init() + { + } +} diff --git a/DiscordNodes/PluginSettings.cs b/DiscordNodes/PluginSettings.cs new file mode 100644 index 00000000..509290a0 --- /dev/null +++ b/DiscordNodes/PluginSettings.cs @@ -0,0 +1,18 @@ +namespace FileFlows.DiscordNodes +{ + using FileFlows.Plugin; + using FileFlows.Plugin.Attributes; + using System; + using System.ComponentModel.DataAnnotations; + + public class PluginSettings:IPluginSettings + { + [Text(1)] + [Required] + public string WebhookId { get; set; } + + [Text(2)] + [Required] + public string WebhookToken { get; set; } + } +} diff --git a/DiscordNodes/Tests/DiscordTests.cs b/DiscordNodes/Tests/DiscordTests.cs new file mode 100644 index 00000000..813c6a56 --- /dev/null +++ b/DiscordNodes/Tests/DiscordTests.cs @@ -0,0 +1,41 @@ +#if(DEBUG) + +using FileFlows.DiscordNodes.Communication; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace FileFlows.DiscordNodes.Tests; + +[TestClass] +public class DiscordTests +{ + [TestMethod] + public void Discord_Simple_Message() + { + var args = new NodeParameters("test.file", new TestLogger(), false, string.Empty); + args.GetPluginSettingsJson = (string input) => + { + return File.ReadAllText("../../../settings.json"); + }; + + var node = new Discord(); + node.Message = "a message"; + Assert.AreEqual(1, node.Execute(args)); + } + + [TestMethod] + public void Discord_Basic_Message() + { + var args = new NodeParameters("test.file", new TestLogger(), false, string.Empty); + args.GetPluginSettingsJson = (string input) => + { + return File.ReadAllText("../../../settings.json"); + }; + + var node = new Discord(); + node.Message = "a message"; + node.MessageType = "Basic"; + Assert.AreEqual(1, node.Execute(args)); + } +} + +#endif \ No newline at end of file diff --git a/DiscordNodes/Tests/TestLogger.cs b/DiscordNodes/Tests/TestLogger.cs new file mode 100644 index 00000000..df21a61b --- /dev/null +++ b/DiscordNodes/Tests/TestLogger.cs @@ -0,0 +1,51 @@ +#if(DEBUG) + +namespace FileFlows.DiscordNodes.Tests; + +using FileFlows.Plugin; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +internal class TestLogger : ILogger +{ + private List Messages = new List(); + + public void DLog(params object[] args) => Log("DBUG", args); + + public void ELog(params object[] args) => Log("ERRR", args); + + public void ILog(params object[] args) => Log("INFO", args); + + public void WLog(params object[] args) => Log("WARN", args); + + private void Log(string type, object[] args) + { + if (args == null || args.Length == 0) + return; + string message = type + " -> " + + string.Join(", ", args.Select(x => + x == null ? "null" : + x.GetType().IsPrimitive || x is string ? x.ToString() : + System.Text.Json.JsonSerializer.Serialize(x))); + Messages.Add(message); + } + + public bool Contains(string message) + { + if (string.IsNullOrWhiteSpace(message)) + return false; + + string log = string.Join(Environment.NewLine, Messages); + return log.Contains(message); + } + + public override string ToString() + { + return String.Join(Environment.NewLine, this.Messages.ToArray()); + } +} + +#endif \ No newline at end of file diff --git a/EmailNodes/EmailNodes.csproj b/EmailNodes/EmailNodes.csproj index e1d6f709..511f9680 100644 Binary files a/EmailNodes/EmailNodes.csproj and b/EmailNodes/EmailNodes.csproj differ diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index ef3f1968..74d6b7b4 100644 Binary files a/FileFlows.Plugin.dll and b/FileFlows.Plugin.dll differ diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index c5abbe14..7e572282 100644 Binary files a/FileFlows.Plugin.pdb and b/FileFlows.Plugin.pdb differ diff --git a/FileFlowsPlugins.sln b/FileFlowsPlugins.sln index c3bb3be6..23fea937 100644 --- a/FileFlowsPlugins.sln +++ b/FileFlowsPlugins.sln @@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicNodes", "MusicNodes\Mu EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmailNodes", "EmailNodes\EmailNodes.csproj", "{8F2739B8-2BD6-4AAC-A54B-2EE1B4AAF559}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordNodes", "DiscordNodes\DiscordNodes.csproj", "{3A74B188-79DB-4A70-B9F1-AF6F767173B6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {8F2739B8-2BD6-4AAC-A54B-2EE1B4AAF559}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F2739B8-2BD6-4AAC-A54B-2EE1B4AAF559}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F2739B8-2BD6-4AAC-A54B-2EE1B4AAF559}.Release|Any CPU.Build.0 = Release|Any CPU + {3A74B188-79DB-4A70-B9F1-AF6F767173B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A74B188-79DB-4A70-B9F1-AF6F767173B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A74B188-79DB-4A70-B9F1-AF6F767173B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A74B188-79DB-4A70-B9F1-AF6F767173B6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MetaNodes/MetaNodes.csproj b/MetaNodes/MetaNodes.csproj index 56b4a48a..961cd822 100644 Binary files a/MetaNodes/MetaNodes.csproj and b/MetaNodes/MetaNodes.csproj differ diff --git a/MusicNodes/MusicNodes.csproj b/MusicNodes/MusicNodes.csproj index 03e4d670..21fe5c61 100644 Binary files a/MusicNodes/MusicNodes.csproj and b/MusicNodes/MusicNodes.csproj differ diff --git a/VideoNodes/VideoNodes.csproj b/VideoNodes/VideoNodes.csproj index b0f21bd0..8903f010 100644 Binary files a/VideoNodes/VideoNodes.csproj and b/VideoNodes/VideoNodes.csproj differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll b/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll index ca764d55..87bddb55 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll and b/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb b/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb index 14977e03..cc9d205f 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb and b/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll index dfc86557..96e971d4 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll and b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb index 02019162..7d8fb6ea 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb and b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.dll b/build/utils/PluginInfoGenerator/FileFlows.Shared.dll index 5fe58097..f189988f 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Shared.dll and b/build/utils/PluginInfoGenerator/FileFlows.Shared.dll differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb b/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb index e76acc2c..71dbf5a8 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb and b/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb differ diff --git a/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll b/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll index 87b73d5b..d8c33e0e 100644 Binary files a/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll and b/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll differ diff --git a/build/utils/PluginInfoGenerator/PluginInfoGenerator.exe b/build/utils/PluginInfoGenerator/PluginInfoGenerator.exe index 95190df1..c9a3679d 100644 Binary files a/build/utils/PluginInfoGenerator/PluginInfoGenerator.exe and b/build/utils/PluginInfoGenerator/PluginInfoGenerator.exe differ diff --git a/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb b/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb index 72af4d4f..93446f17 100644 Binary files a/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb and b/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb differ diff --git a/build/utils/spellcheck/ignoredwords.txt b/build/utils/spellcheck/ignoredwords.txt index 0fb76970..09bf92fd 100644 --- a/build/utils/spellcheck/ignoredwords.txt +++ b/build/utils/spellcheck/ignoredwords.txt @@ -67,4 +67,10 @@ eng remux Scaler SDR -HDR \ No newline at end of file +HDR +Webhook +webhook +api +webhooks +[webhookid] +[webhooktoken] \ No newline at end of file diff --git a/ref/FileFlows.Plugin.dll b/ref/FileFlows.Plugin.dll deleted file mode 100644 index 99314939..00000000 Binary files a/ref/FileFlows.Plugin.dll and /dev/null differ