New custom discord webhook client (#7)
This commit is contained in:
parent
521940ca4f
commit
bb832ed441
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -17,5 +17,7 @@
|
|||||||
"password": "postgres"
|
"password": "postgres"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"editor.formatOnType": true
|
"editor.formatOnType": true,
|
||||||
|
"csharp.inlayHints.parameters.forObjectCreationParameters": true,
|
||||||
|
"omnisharp.organizeImportsOnFormat": true
|
||||||
}
|
}
|
1
DiscordWebhookClient
Submodule
1
DiscordWebhookClient
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d84949a6b735b8e5a079d1d298726da6ca0220e9
|
@ -0,0 +1,8 @@
|
|||||||
|
using Newsbot.Collector.Domain.Models;
|
||||||
|
|
||||||
|
namespace Newsbot.Collector.Domain.Interfaces;
|
||||||
|
|
||||||
|
public interface IDiscordNotificatioClient
|
||||||
|
{
|
||||||
|
void SendMessage(DiscordMessage payload);
|
||||||
|
}
|
@ -6,7 +6,7 @@ public class ArticlesModel
|
|||||||
public Guid SourceID { get; set; }
|
public Guid SourceID { get; set; }
|
||||||
public string Tags { get; set; } = "";
|
public string Tags { get; set; } = "";
|
||||||
public string Title { get; set; } = "";
|
public string Title { get; set; } = "";
|
||||||
public string URL { get; set; } = "";
|
public string? URL { get; set; }
|
||||||
public DateTime PubDate { get; set; } = DateTime.Now;
|
public DateTime PubDate { get; set; } = DateTime.Now;
|
||||||
public string Video { get; set; } = "";
|
public string Video { get; set; } = "";
|
||||||
public int VideoHeight { get; set; } = 0;
|
public int VideoHeight { get; set; } = 0;
|
||||||
@ -14,7 +14,7 @@ public class ArticlesModel
|
|||||||
public string Thumbnail { get; set; } = "";
|
public string Thumbnail { get; set; } = "";
|
||||||
public string Description { get; set; } = "";
|
public string Description { get; set; } = "";
|
||||||
public string AuthorName { get; set; } = "";
|
public string AuthorName { get; set; } = "";
|
||||||
public string AuthorImage { get; set; } = "";
|
public string? AuthorImage { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthorModel
|
public class AuthorModel
|
||||||
|
65
Newsbot.Collector.Domain/Models/DiscordMessage.cs
Normal file
65
Newsbot.Collector.Domain/Models/DiscordMessage.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Newsbot.Collector.Domain.Models;
|
||||||
|
|
||||||
|
public class DiscordMessage
|
||||||
|
{
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public string? Content { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("username")]
|
||||||
|
public string? Username { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("avatar_url")]
|
||||||
|
public string? AvatarUrl { get; set; }
|
||||||
|
//[JsonProperty("thread_name")]
|
||||||
|
//public string ThreadName { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonProperty("embeds")]
|
||||||
|
public DiscordMessageEmbed[]? Embeds { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordMessageEmbedAuthor
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("url")]
|
||||||
|
public string? Url { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("icon_url")]
|
||||||
|
public string? IconUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordMessageEmbedField
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("value")]
|
||||||
|
public string? Value { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("inline")]
|
||||||
|
public bool Inline { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordMessageEmbedImage
|
||||||
|
{
|
||||||
|
[JsonProperty("url")]
|
||||||
|
public string? Url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordMessageEmbedThumbnail
|
||||||
|
{
|
||||||
|
[JsonProperty("url")]
|
||||||
|
public string? Url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordMessageEmbedFooter
|
||||||
|
{
|
||||||
|
[JsonProperty("text")]
|
||||||
|
public string? Text { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("icon_url")]
|
||||||
|
public string? IconUrl { get; set; }
|
||||||
|
}
|
37
Newsbot.Collector.Domain/Models/DiscordMessageEmbed.cs
Normal file
37
Newsbot.Collector.Domain/Models/DiscordMessageEmbed.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Newsbot.Collector.Domain.Models;
|
||||||
|
|
||||||
|
public class DiscordMessageEmbed
|
||||||
|
{
|
||||||
|
[JsonProperty("title")]
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("description")]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("url")]
|
||||||
|
public string? Url { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("color")]
|
||||||
|
public int? Color { get; set; }
|
||||||
|
|
||||||
|
//2023-03-31T07:00:00.000Z
|
||||||
|
//[JsonProperty("timestamp")]
|
||||||
|
//public DateTime TimeStamp { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("author")]
|
||||||
|
public DiscordMessageEmbedAuthor? Author { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("fields")]
|
||||||
|
public DiscordMessageEmbedField[]? Fields { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("image")]
|
||||||
|
public DiscordMessageEmbedImage? Image { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("thumbnail")]
|
||||||
|
public DiscordMessageEmbedThumbnail? Thumbnail { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("footer")]
|
||||||
|
public DiscordMessageEmbedFooter? Footer { get; set; }
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace Newsbot.Collector.Domain.Models;
|
||||||
|
|
||||||
|
public class DiscordMessageEmbedColors
|
||||||
|
{
|
||||||
|
public const int Black = 0;
|
||||||
|
public const int Red = 16711680;
|
||||||
|
public const int DarkBlue = 655615;
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
109
Newsbot.Collector.Services/Jobs/DiscordNotificationJob.cs
Normal file
109
Newsbot.Collector.Services/Jobs/DiscordNotificationJob.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
using Newsbot.Collector.Database.Repositories;
|
||||||
|
using Newsbot.Collector.Domain.Interfaces;
|
||||||
|
using Newsbot.Collector.Domain.Models;
|
||||||
|
using Newsbot.Collector.Services.Notifications.Discord;
|
||||||
|
|
||||||
|
namespace Newsbot.Collector.Services.Jobs;
|
||||||
|
|
||||||
|
public class DiscordNotificationJobOptions
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordNotifificationJob
|
||||||
|
{
|
||||||
|
|
||||||
|
private IDiscordQueueRepository _queue;
|
||||||
|
private IArticlesRepository _article;
|
||||||
|
private IDiscordWebHooksRepository _webhook;
|
||||||
|
private ISourcesRepository _sources;
|
||||||
|
private ISubscriptionRepository _subs;
|
||||||
|
|
||||||
|
private IDiscordNotificatioClient _webhookClient;
|
||||||
|
|
||||||
|
public DiscordNotifificationJob()
|
||||||
|
{
|
||||||
|
_queue = new DiscordQueueTable("");
|
||||||
|
_article = new ArticlesTable("");
|
||||||
|
_webhook = new DiscordWebhooksTable("");
|
||||||
|
_sources = new SourcesTable("");
|
||||||
|
_subs = new SubscriptionsTable("");
|
||||||
|
_webhookClient = new DiscordWebhookClient("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitAndExecute()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Execute()
|
||||||
|
{
|
||||||
|
//collect all the new requests
|
||||||
|
var requests = _queue.List(25);
|
||||||
|
|
||||||
|
foreach (var request in requests)
|
||||||
|
{
|
||||||
|
// Get all details on the article in the queue
|
||||||
|
var articleDetails = _article.GetById(request.ArticleID);
|
||||||
|
|
||||||
|
// Get the deatils of the source
|
||||||
|
var sourceDetails = _sources.GetByID(articleDetails.SourceID);
|
||||||
|
|
||||||
|
// Find all the subscriptions for that source
|
||||||
|
var allSubscriptions = _subs.ListBySourceID(sourceDetails.ID);
|
||||||
|
|
||||||
|
foreach (var sub in allSubscriptions)
|
||||||
|
{
|
||||||
|
// find the discord webhooks we need to post to
|
||||||
|
var discordDetails = _webhook.GetByID(sub.DiscordWebHookID);
|
||||||
|
|
||||||
|
var client = new DiscordWebhookClient(discordDetails.Url);
|
||||||
|
client.SendMessage(GenerateDiscordMessage(sourceDetails, articleDetails));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordMessage GenerateDiscordMessage(SourceModel source, ArticlesModel article)
|
||||||
|
{
|
||||||
|
var embed = new DiscordMessageEmbed
|
||||||
|
{
|
||||||
|
Title = article.Title,
|
||||||
|
Color = DiscordMessageEmbedColors.Red,
|
||||||
|
Description = article.Description,
|
||||||
|
Author = new DiscordMessageEmbedAuthor
|
||||||
|
{
|
||||||
|
Name = article.AuthorName,
|
||||||
|
},
|
||||||
|
Footer = new DiscordMessageEmbedFooter
|
||||||
|
{
|
||||||
|
Text = "Brought to you by Newsbot",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (article.URL is not null && article.URL != "")
|
||||||
|
{
|
||||||
|
embed.Url = article.URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (article.Thumbnail is not null && article.Thumbnail != "")
|
||||||
|
{
|
||||||
|
embed.Image = new DiscordMessageEmbedImage
|
||||||
|
{
|
||||||
|
Url = article.Thumbnail
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (article.AuthorImage is not null && article.AuthorImage != "")
|
||||||
|
{
|
||||||
|
embed.Author.IconUrl = article.AuthorImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DiscordMessage
|
||||||
|
{
|
||||||
|
Embeds = new DiscordMessageEmbed[]
|
||||||
|
{
|
||||||
|
embed
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -131,6 +131,12 @@ public class RssWatcherJob : IHangfireJob
|
|||||||
{
|
{
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
|
if (item.URL is null)
|
||||||
|
{
|
||||||
|
Log.Warning($"RSS Watcher collected a blank url and was skipped.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsThisUrlKnown(item.URL) == true)
|
if (IsThisUrlKnown(item.URL) == true)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using Newsbot.Collector.Domain.Interfaces;
|
||||||
|
using Newsbot.Collector.Domain.Models;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Newsbot.Collector.Services.Notifications.Discord;
|
||||||
|
|
||||||
|
public class DiscordWebhookClient : IDiscordNotificatioClient
|
||||||
|
{
|
||||||
|
|
||||||
|
private string[] _webhooks;
|
||||||
|
|
||||||
|
public DiscordWebhookClient(string webhook)
|
||||||
|
{
|
||||||
|
_webhooks = new string[] { webhook };
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordWebhookClient(string[] webhooks)
|
||||||
|
{
|
||||||
|
_webhooks = webhooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMessage(DiscordMessage payload)
|
||||||
|
{
|
||||||
|
if (payload.Embeds is not null)
|
||||||
|
{
|
||||||
|
MessageValidation.IsEmbedFooterValid(payload.Embeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var webhook in _webhooks)
|
||||||
|
{
|
||||||
|
var jsonRaw = JsonConvert.SerializeObject(payload, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
|
||||||
|
using StringContent jsonContent = new(jsonRaw, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var client = new HttpClient();
|
||||||
|
var resp = client.PostAsync(webhook, jsonContent);
|
||||||
|
resp.Wait();
|
||||||
|
|
||||||
|
if (resp.Result.StatusCode != HttpStatusCode.NoContent)
|
||||||
|
{
|
||||||
|
throw new Exception("Message was not accepted by the sever.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
using Newsbot.Collector.Domain.Models;
|
||||||
|
|
||||||
|
namespace Newsbot.Collector.Services.Notifications.Discord;
|
||||||
|
|
||||||
|
public class MessageValidation
|
||||||
|
{
|
||||||
|
public void IsMessageValid(DiscordMessage payload)
|
||||||
|
{
|
||||||
|
if (payload.Embeds is null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsEmbedFooterValid(DiscordMessageEmbed[] embeds)
|
||||||
|
{
|
||||||
|
if (embeds.Count() == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var embed in embeds)
|
||||||
|
{
|
||||||
|
if (embed.Footer is null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (embed.Footer.IconUrl is null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var containsHttp = embed.Footer.IconUrl.Contains("http://");
|
||||||
|
var containsHttps = embed.Footer.IconUrl.Contains("https://");
|
||||||
|
|
||||||
|
if (containsHttp == false || containsHttps == false)
|
||||||
|
{
|
||||||
|
throw new Exception("Footer.IconUrl does not contain http:// or https://");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsEmbedAuthorValid(DiscordMessageEmbedAuthor author)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user