Skip to content

Commit f1c554c

Browse files
committed
Add CloudEvents support poppastring#671
1 parent 121ce37 commit f1c554c

18 files changed

+571
-178
lines changed

source/DasBlog.Services/ConfigFile/Interfaces/ISiteConfig.cs

+10-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ public interface ISiteConfig
130130

131131
bool EnableCrossposts { get; set; }
132132

133-
bool UseUserCulture { get; set; }
133+
bool EnableCloudEvents { get; set; }
134+
135+
bool UseUserCulture { get; set; }
134136

135137
bool ShowItemSummaryInAggregatedViews { get; set; }
136138

@@ -199,7 +201,13 @@ public interface ISiteConfig
199201
[XmlArray("CrosspostSites")]
200202
CrosspostSite[] CrosspostSiteArray { get; set; }
201203

202-
bool Pop3DeleteAllMessages { get; set; }
204+
[XmlIgnore]
205+
CloudEventsTargetCollection CloudEventsTargets { get; set; }
206+
207+
[XmlArray("CloudEventsTargets")]
208+
CloudEventsTarget[] CloudEventsTargetArray { get; set; }
209+
210+
bool Pop3DeleteAllMessages { get; set; }
203211

204212
bool Pop3LogIgnoredEmails { get; set; }
205213

source/DasBlog.Services/ConfigFile/SiteConfig.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,10 @@ public string Root {
144144
public ContentFilterCollection ContentFilters { get; set; }
145145
public ContentFilter[] ContentFilterArray { get; set; }
146146
public CrosspostSiteCollection CrosspostSites { get; set; }
147-
public CrosspostSite[] CrosspostSiteArray { get; set; }
148-
public bool Pop3DeleteAllMessages { get; set; }
147+
public CloudEventsTargetCollection CloudEventsTargets { get; set; }
148+
public CrosspostSite[] CrosspostSiteArray { get; set; }
149+
public CloudEventsTarget[] CloudEventsTargetArray { get; set; }
150+
public bool Pop3DeleteAllMessages { get; set; }
149151
public bool Pop3LogIgnoredEmails { get; set; }
150152
public bool EnableReferralUrlBlackList { get; set; }
151153
public string ReferralUrlBlackList { get; set; }
@@ -242,6 +244,6 @@ public string Root {
242244
public string MastodonServerUrl { get; set; }
243245

244246
public string MastodonAccount { get; set; }
245-
247+
public bool EnableCloudEvents { get; set; }
246248
}
247249
}

source/DasBlog.Services/IDasBlogSettings.cs

+1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,6 @@ public interface IDasBlogSettings
4949
SendMailInfo GetMailInfo(MailMessage emailmessage);
5050
DateTime GetDisplayTime(DateTime datetime);
5151
DateTime GetCreateTime(DateTime datetime);
52+
string GetRssEntryUrl(string entryId);
5253
}
5354
}

source/DasBlog.Services/Rss/Rss.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ public class RssItem
125125
[XmlAttribute("xml:lang")]
126126
public string Language;
127127

128-
[XmlElement("author")]
128+
[XmlAttribute("id")]
129+
public string Id;
130+
131+
[XmlElement("author")]
129132
public string Author { get; set; }
130133

131134
[XmlElement("title")]

source/DasBlog.Tests/UnitTests/DasBlogSettingTest.cs

+5
Original file line numberDiff line numberDiff line change
@@ -272,5 +272,10 @@ public DateTime GetCreateTime(DateTime datetime)
272272
{
273273
throw new NotImplementedException();
274274
}
275+
276+
public string GetRssEntryUrl(string entryId)
277+
{
278+
throw new NotImplementedException();
279+
}
275280
}
276281
}

source/DasBlog.Tests/UnitTests/SiteConfigTest.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,8 @@ public class SiteConfigTest : ISiteConfig
171171
public string MastodonServerUrl { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
172172
public string MastodonAccount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
173173
public bool AllowMarkdownInComments { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
174-
}
174+
public bool EnableCloudEvents { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
175+
public CloudEventsTargetCollection CloudEventsTargets { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
176+
public CloudEventsTarget[] CloudEventsTargetArray { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
177+
}
175178
}

source/DasBlog.Web.Repositories/BlogManager.cs

+118-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
using System.Net.Mail;
2121
using System.Net;
2222
using System.IO;
23+
using CloudNative.CloudEvents;
24+
using System.Xml.Linq;
25+
using CloudNative.CloudEvents.Http;
26+
using CloudNative.CloudEvents.SystemTextJson;
27+
using System.Net.Http;
2328

2429
namespace DasBlog.Managers
2530
{
@@ -187,22 +192,134 @@ public EntrySaveState CreateEntry(Entry entry)
187192
{
188193
var rtn = InternalSaveEntry(entry, null, null);
189194
LogEvent(EventCodes.EntryAdded, entry);
195+
RaisePostCreatedCloudEvent(entry);
190196
return rtn;
191197
}
192198

199+
200+
private void RaisePostCreatedCloudEvent(Entry entry)
201+
{
202+
var ext = CloudEventAttribute.CreateExtension("tags", CloudEventAttributeType.String);
203+
var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V1_0, new[] { ext })
204+
{
205+
Type = "dasblog.post.created",
206+
Source = new Uri(dasBlogSettings.GetBaseUrl()),
207+
Subject = entry.Link,
208+
Data = MapEntryToCloudEventData(entry),
209+
Id = Guid.NewGuid().ToString(),
210+
Time = DateTime.UtcNow,
211+
};
212+
cloudEvent.SetAttributeFromString("tags", entry.Categories);
213+
RaiseCloudEvent(cloudEvent);
214+
215+
}
216+
217+
private void RaiseCloudEvent(CloudEvent cloudEvent)
218+
{
219+
if ( dasBlogSettings.SiteConfiguration.EnableCloudEvents &&
220+
dasBlogSettings.SiteConfiguration.CloudEventsTargets != null)
221+
{
222+
foreach (var target in dasBlogSettings.SiteConfiguration.CloudEventsTargets)
223+
{
224+
if (!string.IsNullOrEmpty(target.Uri))
225+
{
226+
try
227+
{
228+
var content = cloudEvent.ToHttpContent(ContentMode.Structured, new JsonEventFormatter());
229+
var uriBuilder = new UriBuilder(target.Uri);
230+
if (target.Headers != null)
231+
{
232+
foreach (var header in target.Headers)
233+
{
234+
if (!string.IsNullOrEmpty(header.Name))
235+
{
236+
content.Headers.Add(header.Name, header.Value);
237+
}
238+
}
239+
}
240+
if (target.QueryArgs!= null)
241+
{
242+
foreach (var queryArgs in target.QueryArgs)
243+
{
244+
uriBuilder.Query = (string.IsNullOrEmpty(uriBuilder.Query) ? string.Empty : uriBuilder.Query + "&") + queryArgs.Name + "=" + queryArgs.Value;
245+
}
246+
}
247+
var httpClient = new HttpClient();
248+
var result = httpClient.PostAsync(uriBuilder.Uri, content).GetAwaiter().GetResult();
249+
}
250+
catch(Exception ex)
251+
{
252+
logger.LogError(ex, "Failed to post CloudEvent");
253+
}
254+
}
255+
}
256+
}
257+
}
258+
259+
private EntryCloudEventData MapEntryToCloudEventData(Entry entry)
260+
{
261+
var data = new EntryCloudEventData();
262+
data.Id = entry.EntryId;
263+
data.Title = entry.Title;
264+
data.CreatedUtc = entry.CreatedUtc;
265+
data.ModifiedUtc = entry.ModifiedUtc;
266+
data.Tags = entry.Categories;
267+
data.Description = entry.Description;
268+
data.PermaLink = entry.Link;
269+
data.DetailsLink = dasBlogSettings.GetRssEntryUrl(entry.EntryId);
270+
data.IsPublic = entry.IsPublic;
271+
data.Author = entry.Author;
272+
data.Longitude = entry.Longitude;
273+
data.Latitude = entry.Latitude;
274+
return data;
275+
}
276+
193277
public EntrySaveState UpdateEntry(Entry entry)
194278
{
195279
var rtn = InternalSaveEntry(entry, null, null);
196280
LogEvent(EventCodes.EntryChanged, entry);
281+
RaisePostUpdatedCloudEvent(entry);
197282
return rtn;
198283
}
199284

285+
private void RaisePostUpdatedCloudEvent(Entry entry)
286+
{
287+
var ext = CloudEventAttribute.CreateExtension("tags", CloudEventAttributeType.String);
288+
var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V1_0, new[] { ext })
289+
{
290+
Type = "dasblog.post.updated",
291+
Source = new Uri(dasBlogSettings.GetBaseUrl()),
292+
Subject = entry.Link,
293+
Data = MapEntryToCloudEventData(entry),
294+
Id = Guid.NewGuid().ToString(),
295+
Time = DateTime.UtcNow,
296+
};
297+
cloudEvent.SetAttributeFromString("tags", entry.Categories);
298+
RaiseCloudEvent(cloudEvent);
299+
}
300+
200301
public void DeleteEntry(string postid)
201302
{
202303
var entry = GetEntryForEdit(postid);
203304
dataService.DeleteEntry(postid, null);
204-
205305
LogEvent(EventCodes.EntryDeleted, entry);
306+
RaisePostDeletedCloudEvent(entry);
307+
}
308+
309+
private void RaisePostDeletedCloudEvent(Entry entry)
310+
{
311+
var ext = CloudEventAttribute.CreateExtension("tags", CloudEventAttributeType.String);
312+
var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V1_0, new[] { ext })
313+
{
314+
Type = "dasblog.post.deleted",
315+
Source = new Uri(dasBlogSettings.GetBaseUrl()),
316+
Subject = entry.Link,
317+
Id = Guid.NewGuid().ToString(),
318+
Time = DateTime.UtcNow,
319+
Data = MapEntryToCloudEventData(entry)
320+
};
321+
cloudEvent.SetAttributeFromString("tags", entry.Categories);
322+
RaiseCloudEvent(cloudEvent);
206323
}
207324

208325
private static StringCollection GetSearchWords(string searchString)

source/DasBlog.Web.Repositories/DasBlog.Managers.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1111
</PropertyGroup>
1212
<ItemGroup>
13+
<PackageReference Include="CloudNative.CloudEvents" Version="2.5.1" />
14+
<PackageReference Include="CloudNative.CloudEvents.SystemTextJson" Version="2.5.1" />
1315
<PackageReference Include="NodaTime" Version="3.0.9" />
1416
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
1517
</ItemGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Text.Json.Serialization;
3+
4+
namespace DasBlog.Managers
5+
{
6+
internal class EntryCloudEventData
7+
{
8+
[JsonPropertyName("id")]
9+
public string Id { get; internal set; }
10+
[JsonPropertyName("title")]
11+
public string Title { get; internal set; }
12+
[JsonPropertyName("createdUtc")]
13+
public DateTime CreatedUtc { get; internal set; }
14+
[JsonPropertyName("modifiedUtc")]
15+
public DateTime ModifiedUtc { get; internal set; }
16+
[JsonPropertyName("tags")]
17+
public string Tags { get; internal set; }
18+
[JsonPropertyName("description")]
19+
public string Description { get; internal set; }
20+
[JsonPropertyName("permaLink")]
21+
public string PermaLink { get; internal set; }
22+
[JsonPropertyName("contentLink")]
23+
public string DetailsLink { get; internal set; }
24+
[JsonPropertyName("isPublic")]
25+
public bool IsPublic { get; internal set; }
26+
[JsonPropertyName("author")]
27+
public string Author { get; internal set; }
28+
[JsonPropertyName("longitude")]
29+
public double? Longitude { get; internal set; }
30+
[JsonPropertyName("latitude")]
31+
public double? Latitude { get; internal set; }
32+
33+
}
34+
}

source/DasBlog.Web.Repositories/Interfaces/ISubscriptionManager.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ public interface ISubscriptionManager
1010
RssRoot GetAtom();
1111
RssRoot GetAtomCategory(string categoryName);
1212
RsdRoot GetRsd();
13-
}
13+
RssItem GetRssItem(string entryId);
14+
}
1415
}

0 commit comments

Comments
 (0)