FF-1353 - created pushover plugin

This commit is contained in:
John Andrews
2024-02-20 14:10:09 +13:00
parent d726212ab0
commit 4ec0a68c0e
10 changed files with 433 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
using System.ComponentModel;
using System.Text.Json;
namespace FileFlows.Pushover.Communication;
/// <summary>
/// A Pushover flow element that sends a message
/// </summary>
public class Pushover: 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 => "fab fa-product-hunt";
/// <summary>
/// Gets if this can be used in a failure flow
/// </summary>
public override bool FailureNode => true;
/// <inheritdoc />
public override string CustomColor => "#40a6eb";
/// <summary>
/// Gets the Help URL
/// </summary>
public override string HelpUrl => "https://fileflows.com/docs/plugins/pushover";
/// <summary>
/// Gets or sets the priority of the message
/// </summary>
[Select(nameof(Priorities), 1)]
[DefaultValue(0)]
public int Priority { get; set; } = 2;
/// <summary>
/// Gets or sets the expiry in seconds for the message
/// </summary>
[ConditionEquals(nameof(Priority), 2)]
[NumberInt(2)]
[DefaultValue(600)]
[Range(1, 86400)]
public int Expire { get; set; } = 2;
/// <summary>
/// Gets or sets the retry time in seconds
/// </summary>
[ConditionEquals(nameof(Priority), 2)]
[NumberInt(2)]
[DefaultValue(600)]
[Range(30, 86400)]
public int Retry { get; set; } = 2;
private static List<ListOption> _Priorities;
/// <summary>
/// Gets a list of message templates
/// </summary>
public static List<ListOption> Priorities
{
get
{
if (_Priorities == null)
{
_Priorities = new List<ListOption>
{
new () { Label = "Lowest", Value = -1 },
new () { Label = "Normal", Value = 0 },
new () { Label = "High", Value = 1 },
new () { Label = "Emergency", Value = 2 }
};
}
return _Priorities;
}
}
/// <summary>
/// Gets or sets the message
/// </summary>
[Required]
[Template(3, nameof(MessageTemplates))]
public string Message { get; set; }
private static List<ListOption> _MessageTemplates;
/// <summary>
/// Gets a list of message templates
/// </summary>
public static List<ListOption> MessageTemplates
{
get
{
if (_MessageTemplates == null)
{
_MessageTemplates = new List<ListOption>
{
new () { Label = "Basic", Value = @"File: {{ file.Orig.FullName }}
Size: {{ file.Size }}" },
new () { Label = "File Size Changes", Value = @"
{{ difference = file.Size - file.Orig.Size }}
{{ percent = (difference / file.Orig.Size) * 100 | math.round 2 }}
Input File: {{ file.Orig.FullName }}
Output File: {{ file.FullName }}
Original Size: {{ file.Orig.Size | file_size }}
Final Size: {{ file.Size | file_size }}
{{- if difference < 0 }}
File grew in size: {{ difference | math.abs | file_size }}
{{ else }}
File shrunk in size by: {{ difference | file_size }} / {{ percent }}%
{{ end }}"}
};
}
return _MessageTemplates;
}
}
/// <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 (string.IsNullOrWhiteSpace(settings?.UserKey))
{
args.Logger?.WLog("No user set");
return 2;
}
if (string.IsNullOrWhiteSpace(settings?.ApiToken))
{
args.Logger?.WLog("No API Token set");
return 2;
}
string message = args.RenderTemplate!(this.Message);
if (string.IsNullOrWhiteSpace(message))
{
args.Logger?.WLog("No message to send");
return 2;
}
List<KeyValuePair<string, string>> parameters = new ()
{
new ("token", settings.ApiToken),
new ("user", settings.UserKey),
new ("message", message),
new ("priority", Priority.ToString())
};
if (Priority == 2)
{
int expire = Expire < 1 ? 1 : (Expire > 86400 ? 86400 : Expire);
parameters.Add(new("expire", expire.ToString()));
int retry = Retry < 30 ? 30 : (Retry > 86400 ? 86400 : Retry);
parameters.Add(new("retry", retry.ToString()));
}
var content = new FormUrlEncodedContent(parameters);
using var httpClient = new HttpClient();
var response = httpClient.PostAsync("https://api.pushover.net/1/messages.json", content).Result;
if (response.IsSuccessStatusCode)
return 1;
string error = response.Content.ReadAsStringAsync().Result;
args.Logger?.WLog("Error from Pushover: " + error);
return 2;
}
catch (Exception ex)
{
args.Logger?.WLog("Error sending message: " + ex.Message);
return 2;
}
}
}

View File

@@ -0,0 +1,14 @@
namespace FileFlows.Pushover;
/// <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
Pushover/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
Pushover/Plugin.cs Normal file
View File

@@ -0,0 +1,29 @@
namespace FileFlows.Pushover;
/// <summary>
/// A Pushover Plugin
/// </summary>
public class Plugin : FileFlows.Plugin.IPlugin
{
/// <summary>
/// Gets the UID for this plugin
/// </summary>
public Guid Uid => new Guid("99cc0b7e-e470-4829-9a3b-30e8cc2ee749");
/// <summary>
/// Gets the name of this plugin
/// </summary>
public string Name => "Pushover";
/// <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.Pushover;
/// <summary>
/// The plugin settings for this plugin
/// </summary>
public class PluginSettings : IPluginSettings
{
/// <summary>
/// Gets or sets the user key to send the push over notification to
/// </summary>
[Text(1)]
[Required]
public string UserKey { get; set; }
/// <summary>
/// Gets or sets the API Token
/// </summary>
[Text(2)]
[Required]
public string ApiToken { get; set; }
}

41
Pushover/Pushover.csproj Normal file
View File

@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>FileFlows.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
<FileVersion>1.1.1.528</FileVersion>
<ProductVersion>1.1.1.528</ProductVersion>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<PublishTrimmed>true</PublishTrimmed>
<Company>FileFlows</Company>
<Authors>John Andrews</Authors>
<Product>Pushover</Product>
<PackageProjectUrl>https://fileflows.com/</PackageProjectUrl>
<Description>Lets you send Pushover messages to a server</Description>
</PropertyGroup>
<ItemGroup>
<None Remove="Pushover.en.json" />
</ItemGroup>
<ItemGroup>
<Content Include="Pushover.en.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Debug'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.4" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.4" />
</ItemGroup>
<ItemGroup>
<Reference Include="FileFlows.Plugin">
<HintPath>..\FileFlows.Plugin.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

36
Pushover/Pushover.en.json Normal file
View File

@@ -0,0 +1,36 @@
{
"Plugins": {
"Pushover": {
"Description": "A plugin that allows you to send messages to a Pushover server.",
"Fields": {
"UserKey": "User Key",
"UserKey-Help":"Your personal user key for receiving notifications.",
"ApiToken": "API Token",
"ApiToken-Help":"The application API token use for sending notifications."
}
}
},
"Flow": {
"Parts": {
"Pushover": {
"Outputs": {
"1": "Pushover message sent",
"2": "Pushover message failed to send"
},
"Description": "Sends a message via Pushover.",
"Fields": {
"Message": "Message",
"Message-Help": "The message to send to the Pushover server",
"Expire": "Expire",
"Expire-Suffix": "seconds",
"Expire-Help": "Set the duration, in seconds, before this emergency message expires and stops retrying delivery.",
"Retry": "Retry",
"Retry-Suffix": "seconds",
"Retry-Help": "Specify the interval, in seconds, between retry attempts for this emergency message in case of delivery failure.",
"Priority": "Priority",
"Priority-Help": "The priority of the message being sent"
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
#if(DEBUG)
using FileFlows.Pushover.Communication;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FileFlows.Pushover.Tests;
[TestClass]
public class PushoverTests
{
[TestMethod]
public void Pushover_Basic_Message()
{
var args = new NodeParameters("test.file", new TestLogger(), false, string.Empty, null);
args.GetPluginSettingsJson = (string input) =>
{
return File.ReadAllText("../../../../../pushover.json");
};
var node = new FileFlows.Pushover.Communication.Pushover();
node.Message = "a message";
Assert.AreEqual(1, node.Execute(args));
}
}
#endif

View File

@@ -0,0 +1,59 @@
#if(DEBUG)
namespace FileFlows.Pushover.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