FF-1135 - added telegram plugin

This commit is contained in:
John Andrews
2023-10-24 09:15:17 +13:00
parent 954fdb54d8
commit 18a03d5e13
13 changed files with 363 additions and 17 deletions

View File

@@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudioNodes", "AudioNodes\Au
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComicNodes", "ComicNodes\ComicNodes.csproj", "{45568FCB-00FF-4AEA-AA43-DC569D667B04}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegram", "Telegram\Telegram.csproj", "{BFAD621E-4C82-47FC-A9C8-03F09FF9926C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -87,6 +89,10 @@ Global
{45568FCB-00FF-4AEA-AA43-DC569D667B04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45568FCB-00FF-4AEA-AA43-DC569D667B04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45568FCB-00FF-4AEA-AA43-DC569D667B04}.Release|Any CPU.Build.0 = Release|Any CPU
{BFAD621E-4C82-47FC-A9C8-03F09FF9926C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFAD621E-4C82-47FC-A9C8-03F09FF9926C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFAD621E-4C82-47FC-A9C8-03F09FF9926C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFAD621E-4C82-47FC-A9C8-03F09FF9926C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -3,26 +3,58 @@ using System.Text.Json;
namespace FileFlows.Gotify.Communication;
/// <summary>
/// A Gotify flow element that sends a message
/// </summary>
public class Gotify: Node
{
/// <summary>
/// Gets the number of inputs to this flow element
/// </summary>
public override int Inputs => 1;
/// <summary>
/// Gets the number of outputs to this flow element
/// </summary>
public override int Outputs => 2;
public override FlowElementType Type => FlowElementType.Communication;
/// <summary>
/// Gets the type of flow element
/// </summary>
public override FlowElementType Type => FlowElementType.Communication;
/// <summary>
/// Gets the icon for this flow element
/// </summary>
public override string Icon => "fas fa-bell";
/// <summary>
/// Gets if this can be used in a failure flow
/// </summary>
public override bool FailureNode => true;
/// <summary>
/// Gets or sets the message to send
/// </summary>
[Required]
[TextVariable(1)]
public string Message { get; set; }
/// <summary>
/// Gets or sets the title of the message
/// </summary>
[TextVariable(2)]
public string Title { get; set; }
/// <summary>
/// Gets or sets the priority of the message
/// </summary>
[NumberInt(3)]
[Range(1, 100)]
[DefaultValue(2)]
public int Priority { get; set; } = 2;
/// <summary>
/// Executes the flow element
/// </summary>
/// <param name="args">the node parameters</param>
/// <returns>the output to call next</returns>
public override int Execute(NodeParameters args)
{
try

View File

@@ -1,6 +1,14 @@
namespace FileFlows.Gotify;
/// <summary>
/// Extension methods
/// </summary>
internal static class ExtensionMethods
{
/// <summary>
/// Returns an empty string as null, otherwise returns the original string
/// </summary>
/// <param name="str">the input string</param>
/// <returns>the string or null if empty</returns>
public static string? EmptyAsNull(this string str) => str == string.Empty ? null : str;
}

View File

@@ -1,11 +1,28 @@
namespace FileFlows.Gotify;
/// <summary>
/// A Gotify Plugin
/// </summary>
public class Plugin : FileFlows.Plugin.IPlugin
{
/// <summary>
/// Gets the UID for this plugin
/// </summary>
public Guid Uid => new Guid("3d8e13f2-819f-437f-b177-be40147c6e2b");
/// <summary>
/// Gets the name of this plugin
/// </summary>
public string Name => "Gotify Nodes";
/// <summary>
/// Gets the minimum version of FileFlows required for this plugin
/// </summary>
public string MinimumVersion => "1.0.4.2019";
/// <summary>
/// Initializes this plugin
/// </summary>
public void Init()
{
}

View File

@@ -1,18 +1,21 @@
namespace FileFlows.Gotify
namespace FileFlows.Gotify;
/// <summary>
/// The plugin settings for this plugin
/// </summary>
public class PluginSettings : IPluginSettings
{
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
using System;
using System.ComponentModel.DataAnnotations;
/// <summary>
/// Gets or sets the URL to the server to send messages to
/// </summary>
[Text(1)]
[Required]
public string ServerUrl { get; set; }
public class PluginSettings:IPluginSettings
{
[Text(1)]
[Required]
public string ServerUrl { get; set; }
[Text(2)]
[Required]
public string AccessToken { get; set; }
}
/// <summary>
/// Gets or sets the Access Token for the server
/// </summary>
[Text(2)]
[Required]
public string AccessToken { get; set; }
}

View File

@@ -0,0 +1,101 @@
namespace FileFlows.Telegram.Communication;
/// <summary>
/// A Telegram flow element that sends a message
/// </summary>
public class Telegram: Node
{
/// <summary>
/// Gets the number of inputs to this flow element
/// </summary>
public override int Inputs => 1;
/// <summary>
/// Gets the number of outputs to this flow element
/// </summary>
public override int Outputs => 2;
/// <summary>
/// Gets the type of flow element
/// </summary>
public override FlowElementType Type => FlowElementType.Communication;
/// <summary>
/// Gets the icon for this flow element
/// </summary>
public override string Icon => "fas fa-bell";
/// <summary>
/// Gets if this can be used in a failure flow
/// </summary>
public override bool FailureNode => true;
/// <summary>
/// Gets or sets the message to send
/// </summary>
[Required]
[TextVariable(1)]
public string Message { get; set; }
/// <summary>
/// Sends a telegram message
/// </summary>
/// <param name="botToken">the bot token</param>
/// <param name="chatId">the chat id</param>
/// <param name="message">the message to send</param>
/// <returns>true if successful, otherwise false</returns>
internal static bool SendMessage(string botToken, string chatId, string message)
{
using (HttpClient client = new HttpClient())
{
string apiUrl = $"https://api.telegram.org/bot{botToken}/sendMessage";
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("chat_id", chatId.ToString()),
new KeyValuePair<string, string>("text", message)
});
var response = client.PostAsync(apiUrl, content).Result;
return response.IsSuccessStatusCode;
}
}
/// <summary>
/// Executes the flow element
/// </summary>
/// <param name="args">the node parameters</param>
/// <returns>the output to call next</returns>
public override int Execute(NodeParameters args)
{
try
{
var settings = args.GetPluginSettings<PluginSettings>();
if (settings == null)
{
args.Logger?.ILog("Failed to load plugin settings");
return 2;
}
if (string.IsNullOrWhiteSpace(settings?.BotToken))
{
args.Logger?.WLog("No Bot Token set");
return 2;
}
if (string.IsNullOrWhiteSpace(settings?.ChatId))
{
args.Logger?.WLog("No Chat ID set");
return 2;
}
var message = args.ReplaceVariables(Message);
var result = SendMessage(settings.BotToken, settings.ChatId, message);
return result ? 1 : 2;
}
catch (Exception ex)
{
args.Logger?.WLog("Error sending message: " + ex.Message);
return 2;
}
}
}

View File

@@ -0,0 +1,14 @@
namespace FileFlows.Telegram;
/// <summary>
/// Extension methods
/// </summary>
internal static class ExtensionMethods
{
/// <summary>
/// Returns an empty string as null, otherwise returns the original string
/// </summary>
/// <param name="str">the input string</param>
/// <returns>the string or null if empty</returns>
public static string? EmptyAsNull(this string str) => str == string.Empty ? null : str;
}

5
Telegram/GlobalUsings.cs Normal file
View File

@@ -0,0 +1,5 @@
global using System;
global using System.Text;
global using System.ComponentModel.DataAnnotations;
global using FileFlows.Plugin;
global using FileFlows.Plugin.Attributes;

29
Telegram/Plugin.cs Normal file
View File

@@ -0,0 +1,29 @@
namespace FileFlows.Telegram;
/// <summary>
/// A Telegram Plugin
/// </summary>
public class Plugin : FileFlows.Plugin.IPlugin
{
/// <summary>
/// Gets the UID for this plugin
/// </summary>
public Guid Uid => new Guid("a610837d-c6d6-438b-8470-33a407ea7c98");
/// <summary>
/// Gets the name of this plugin
/// </summary>
public string Name => "Telegram";
/// <summary>
/// Gets the minimum version of FileFlows required for this plugin
/// </summary>
public string MinimumVersion => "1.0.4.2019";
/// <summary>
/// Initializes this plugin
/// </summary>
public void Init()
{
}
}

View File

@@ -0,0 +1,21 @@
namespace FileFlows.Telegram;
/// <summary>
/// The plugin settings for this plugin
/// </summary>
public class PluginSettings : IPluginSettings
{
/// <summary>
/// Gets or sets the bot token
/// </summary>
[Text(1)]
[Required]
public string BotToken { get; set; }
/// <summary>
/// Gets or sets the chat ID
/// </summary>
[Text(1)]
[Required]
public string ChatId { get; set; }
}

28
Telegram/Telegram.en.json Normal file
View File

@@ -0,0 +1,28 @@
{
"Plugins": {
"Telegram": {
"Description": "A plugin that allows you to send Telegram messages.",
"Fields": {
"BotToken": "Bot Token",
"BotToken-Help":"Your telegram bot token.",
"ChatId": "Chat ID",
"ChatId-Help":"The ID of the chat to send messages to."
}
}
},
"Flow": {
"Parts": {
"Telegram": {
"Outputs": {
"1": "Telegram message sent",
"2": "Telegram message failed to send"
},
"Description": "Sends a Telegram message.",
"Fields": {
"Message": "Message",
"Message-Help": "The message to send."
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
#if(DEBUG)
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FileFlows.Telegram.Tests;
[TestClass]
public class TelegramTests
{
[TestMethod]
public void SendMessage()
{
string botToken = "sometoken";
string chatId = "somechat";
var result =
Communication.Telegram.SendMessage(botToken, chatId, "this is a test");
Assert.IsTrue(result);
}
}
#endif

View File

@@ -0,0 +1,59 @@
#if(DEBUG)
namespace FileFlows.Telegram.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<string> Messages = new List<string>();
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());
}
public string GetTail(int length = 50)
{
if (length <= 0)
length = 50;
if (Messages.Count <= length)
return string.Join(Environment.NewLine, Messages);
return string.Join(Environment.NewLine, Messages.TakeLast(length));
}
}
#endif