-
-
Notifications
You must be signed in to change notification settings - Fork 398
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2095 from tidusjar/feature/mattermost-fix
- Loading branch information
Showing
5 changed files
with
381 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
/// | ||
/// | ||
/// | ||
/// Code taken from https://github.com/PromoFaux/Matterhook.NET.MatterhookClient | ||
/// | ||
/// | ||
/// | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Net.Http; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Newtonsoft.Json; | ||
|
||
namespace Ombi.Api.Mattermost.Models | ||
{ | ||
public class MatterhookClient | ||
{ | ||
private readonly Uri _webhookUrl; | ||
private readonly HttpClient _httpClient = new HttpClient(); | ||
|
||
/// <summary> | ||
/// Create a new Mattermost Client | ||
/// </summary> | ||
/// <param name="webhookUrl">The URL of your Mattermost Webhook</param> | ||
/// <param name="timeoutSeconds">Timeout Value (Default 100)</param> | ||
public MatterhookClient(string webhookUrl, int timeoutSeconds = 100) | ||
{ | ||
if (!Uri.TryCreate(webhookUrl, UriKind.Absolute, out _webhookUrl)) | ||
throw new ArgumentException("Mattermost URL invalid"); | ||
|
||
_httpClient.Timeout = new TimeSpan(0, 0, 0, timeoutSeconds); | ||
} | ||
|
||
public MattermostMessage CloneMessage(MattermostMessage inMsg) | ||
{ | ||
var outMsg = new MattermostMessage | ||
{ | ||
Text = "", | ||
Channel = inMsg.Channel, | ||
Username = inMsg.Username, | ||
IconUrl = inMsg.IconUrl | ||
}; | ||
|
||
return outMsg; | ||
} | ||
|
||
private static MattermostAttachment CloneAttachment(MattermostAttachment inAtt) | ||
{ | ||
var outAtt = new MattermostAttachment | ||
{ | ||
AuthorIcon = inAtt.AuthorIcon, | ||
AuthorLink = inAtt.AuthorLink, | ||
AuthorName = inAtt.AuthorName, | ||
Color = inAtt.Color, | ||
Fallback = inAtt.Fallback, | ||
Fields = inAtt.Fields, | ||
ImageUrl = inAtt.ImageUrl, | ||
Pretext = inAtt.Pretext, | ||
ThumbUrl = inAtt.ThumbUrl, | ||
Title = inAtt.Title, | ||
TitleLink = inAtt.TitleLink, | ||
Text = "" | ||
}; | ||
return outAtt; | ||
} | ||
|
||
/// <summary> | ||
/// Post Message to Mattermost server. Messages will be automatically split if total text length > 4000 | ||
/// </summary> | ||
/// <param name="api"></param> | ||
/// <param name="inMessage">The messsage you wish to send</param> | ||
/// <returns></returns> | ||
public async Task PostAsync(IApi api, MattermostMessage inMessage) | ||
{ | ||
try | ||
{ | ||
var outMessages = new List<MattermostMessage>(); | ||
|
||
var msgCount = 0; | ||
|
||
var lines = new string[] { }; | ||
if (inMessage.Text != null) | ||
{ | ||
lines = inMessage.Text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); | ||
} | ||
|
||
//start with one cloned inMessage in the list | ||
outMessages.Add(CloneMessage(inMessage)); | ||
|
||
//add text from original. If we go over 3800, we'll split it to a new inMessage. | ||
foreach (var line in lines) | ||
{ | ||
|
||
if (line.Length + outMessages[msgCount].Text.Length > 3800) | ||
{ | ||
|
||
msgCount += 1; | ||
outMessages.Add(CloneMessage(inMessage)); | ||
} | ||
|
||
outMessages[msgCount].Text += $"{line}\r\n"; | ||
} | ||
|
||
//Length of text on the last (or first if only one) inMessage. | ||
var lenMessageText = outMessages[msgCount].Text.Length; | ||
|
||
//does our original have attachments? | ||
if (inMessage.Attachments?.Any() ?? false) | ||
{ | ||
outMessages[msgCount].Attachments = new List<MattermostAttachment>(); | ||
|
||
//loop through them in a similar fashion to the inMessage text above. | ||
foreach (var att in inMessage.Attachments) | ||
{ | ||
//add this attachment to the outgoing message | ||
outMessages[msgCount].Attachments.Add(CloneAttachment(att)); | ||
//get a count of attachments on this message, and subtract one so we know the index of the current new attachment | ||
var attIndex = outMessages[msgCount].Attachments.Count - 1; | ||
|
||
//Get the text lines | ||
lines = att.Text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); | ||
|
||
foreach (var line in lines) | ||
{ | ||
//Get the total length of all attachments on the current outgoing message | ||
var lenAllAttsText = outMessages[msgCount].Attachments.Sum(a => a.Text.Length); | ||
|
||
if (lenMessageText + lenAllAttsText + line.Length > 3800) | ||
{ | ||
msgCount += 1; | ||
attIndex = 0; | ||
outMessages.Add(CloneMessage(inMessage)); | ||
outMessages[msgCount].Attachments = new List<MattermostAttachment> { CloneAttachment(att) }; | ||
} | ||
|
||
outMessages[msgCount].Attachments[attIndex].Text += $"{line}\r\n"; | ||
} | ||
} | ||
} | ||
|
||
|
||
if (outMessages.Count > 1) | ||
{ | ||
var num = 1; | ||
foreach (var msg in outMessages) | ||
{ | ||
msg.Text = $"`({num}/{msgCount + 1}): ` " + msg.Text; | ||
num++; | ||
} | ||
} | ||
|
||
foreach (var msg in outMessages) | ||
{ | ||
var request = new Request("", _webhookUrl.ToString(), HttpMethod.Post); | ||
request.AddJsonBody(msg); | ||
await api.Request(request); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Console.WriteLine(e.Message); | ||
throw; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/// | ||
/// | ||
/// | ||
/// Code taken from https://github.com/PromoFaux/Matterhook.NET.MatterhookClient | ||
/// | ||
/// | ||
/// | ||
using System; | ||
using System.Collections.Generic; | ||
using Newtonsoft.Json; | ||
|
||
namespace Ombi.Api.Mattermost.Models | ||
|
||
{ | ||
public class MattermostMessage | ||
{ | ||
|
||
//https://docs.mattermost.com/developer/webhooks-incoming.html | ||
|
||
/// <summary> | ||
/// Channel to post to | ||
/// </summary> | ||
[JsonProperty(PropertyName = "channel")] | ||
public string Channel { get; set; } | ||
|
||
/// <summary> | ||
/// Username for bot | ||
/// </summary> | ||
[JsonProperty(PropertyName = "username")] | ||
public string Username { get; set; } | ||
|
||
/// <summary> | ||
/// Bot/User Icon | ||
/// </summary> | ||
[JsonProperty(PropertyName = "icon_url")] | ||
public Uri IconUrl { get; set; } | ||
|
||
/// <summary> | ||
/// Message body. Supports Markdown | ||
/// </summary> | ||
[JsonProperty(PropertyName = "text")] | ||
public string Text { get; set; } | ||
|
||
/// <summary> | ||
/// Richtext attachments | ||
/// </summary> | ||
[JsonProperty(PropertyName = "attachments")] | ||
public List<MattermostAttachment> Attachments { get; set; } | ||
|
||
} | ||
|
||
/// <summary> | ||
/// https://docs.mattermost.com/developer/message-attachments.html#message-attachments | ||
/// </summary> | ||
public class MattermostAttachment | ||
{ | ||
//https://docs.mattermost.com/developer/message-attachments.html#attachment-options | ||
#region AttachmentOptions | ||
|
||
/// <summary> | ||
/// A required plain-text summary of the post. This is used in notifications, and in clients that don’t support formatted text (eg IRC). | ||
/// </summary> | ||
[JsonProperty(PropertyName = "fallback")] | ||
public string Fallback { get; set; } | ||
|
||
/// <summary> | ||
/// A hex color code that will be used as the left border color for the attachment. If not specified, it will default to match the left hand sidebar header background color. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "color")] | ||
public string Color { get; set; } | ||
|
||
/// <summary> | ||
/// Optional text that should appear above the formatted data | ||
/// </summary> | ||
[JsonProperty(PropertyName = "pretext")] | ||
public string Pretext { get; set; } | ||
|
||
/// <summary> | ||
/// The text to be included in the attachment. It can be formatted using Markdown. If it includes more than 300 characters or more than 5 line breaks, the message will be collapsed and a “Show More” link will be added to expand the message. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "text")] | ||
public string Text { get; set; } | ||
|
||
#endregion | ||
|
||
//https://docs.mattermost.com/developer/message-attachments.html#author-details | ||
#region AuthorDetails | ||
|
||
/// <summary> | ||
/// An optional name used to identify the author. It will be included in a small section at the top of the attachment. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "author_name")] | ||
public string AuthorName { get; set; } | ||
|
||
/// <summary> | ||
/// An optional URL used to hyperlink the author_name. If no author_name is specified, this field does nothing. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "author_link")] | ||
public Uri AuthorLink { get; set; } | ||
|
||
/// <summary> | ||
/// An optional URL used to display a 16x16 pixel icon beside the author_name. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "author_icon")] | ||
public Uri AuthorIcon { get; set; } | ||
|
||
#endregion | ||
|
||
//https://docs.mattermost.com/developer/message-attachments.html#titles | ||
#region Titles | ||
|
||
/// <summary> | ||
/// An optional title displayed below the author information in the attachment. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "title")] | ||
public string Title { get; set; } | ||
|
||
/// <summary> | ||
/// An optional URL used to hyperlink the title. If no title is specified, this field does nothing. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "title_link")] | ||
public Uri TitleLink { get; set; } | ||
|
||
#endregion | ||
|
||
|
||
#region Fields | ||
|
||
/// <summary> | ||
/// Fields can be included as an optional array within attachments, and are used to display information in a table format inside the attachment. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "fields")] | ||
public List<MattermostField> Fields { get; set; } | ||
|
||
#endregion | ||
|
||
//https://docs.mattermost.com/developer/message-attachments.html#images | ||
#region Images | ||
|
||
/// <summary> | ||
/// An optional URL to an image file (GIF, JPEG, PNG, or BMP) that is displayed inside a message attachment. | ||
/// Large images are resized to a maximum width of 400px or a maximum height of 300px, while still maintaining the original aspect ratio. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "image_url")] | ||
public Uri ImageUrl { get; set; } | ||
|
||
/// <summary> | ||
/// An optional URL to an image file(GIF, JPEG, PNG, or BMP) that is displayed as a 75x75 pixel thumbnail on the right side of an attachment. | ||
/// We recommend using an image that is already 75x75 pixels, but larger images will be scaled down with the aspect ratio maintained. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "thumb_url")] | ||
public Uri ThumbUrl { get; set; } | ||
|
||
|
||
#endregion | ||
} | ||
|
||
/// <summary> | ||
/// https://docs.mattermost.com/developer/message-attachments.html#fieldshttps://docs.mattermost.com/developer/message-attachments.html#fields | ||
/// </summary> | ||
public class MattermostField | ||
{ | ||
/// <summary> | ||
/// A title shown in the table above the value. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "title")] | ||
public string Title { get; set; } | ||
|
||
/// <summary> | ||
/// The text value of the field. It can be formatted using Markdown. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "value")] | ||
public string Value { get; set; } | ||
|
||
/// <summary> | ||
/// Optionally set to “True” or “False” to indicate whether the value is short enough to be displayed beside other values. | ||
/// </summary> | ||
[JsonProperty(PropertyName = "short")] | ||
public bool Short { get; set; } | ||
} | ||
} |
Oops, something went wrong.