diff options
author | crupest <crupest@outlook.com> | 2021-03-06 22:51:53 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-03-06 22:51:53 +0800 |
commit | 8f09e3172f249a9f5d229040415a0569e9d1c01b (patch) | |
tree | 59507331750831118e7caa071a10e1cb8fc1e627 | |
parent | 24c272403ba360f27acd68c2702c678a86063964 (diff) | |
download | timeline-8f09e3172f249a9f5d229040415a0569e9d1c01b.tar.gz timeline-8f09e3172f249a9f5d229040415a0569e9d1c01b.tar.bz2 timeline-8f09e3172f249a9f5d229040415a0569e9d1c01b.zip |
feat: Auto translate url in markdown post.
-rw-r--r-- | BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs | 32 | ||||
-rw-r--r-- | BackEnd/Timeline.Tests/packages.lock.json | 6 | ||||
-rw-r--r-- | BackEnd/Timeline/Controllers/TimelinePostController.cs | 15 | ||||
-rw-r--r-- | BackEnd/Timeline/Services/MarkdownProcessor.cs | 52 | ||||
-rw-r--r-- | BackEnd/Timeline/Startup.cs | 2 | ||||
-rw-r--r-- | BackEnd/Timeline/Timeline.csproj | 1 | ||||
-rw-r--r-- | BackEnd/Timeline/packages.lock.json | 6 |
7 files changed, 112 insertions, 2 deletions
diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index b91de6c2..f00d9b13 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -14,6 +14,7 @@ using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Jpeg;
using System.Net;
+using System.Text.RegularExpressions;
namespace Timeline.Tests.IntegratedTests
{
@@ -36,6 +37,23 @@ namespace Timeline.Tests.IntegratedTests };
}
+ private static HttpTimelinePostCreateRequest CreateMarkdownPostRequest(string text, DateTime? time = null, string? color = null)
+ {
+ return new HttpTimelinePostCreateRequest()
+ {
+ Time = time,
+ Color = color,
+ DataList = new List<HttpTimelinePostCreateRequestData>()
+ {
+ new HttpTimelinePostCreateRequestData()
+ {
+ ContentType = MimeTypes.TextMarkdown,
+ Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(text))
+ }
+ }
+ };
+ }
+
private readonly ITestOutputHelper _outputHelper;
public TimelinePostTest(ITestOutputHelper outputHelper)
@@ -586,5 +604,19 @@ namespace Timeline.Tests.IntegratedTests post2.Editable.Should().BeFalse();
}
}
+
+ [Theory]
+ [MemberData(nameof(TimelineNameGeneratorTestData))]
+ public async Task Post_Markdown_Url_Map(TimelineNameGenerator generator)
+ {
+ using var client = await CreateClientAsUser();
+ var post = await client.TestPostAsync<HttpTimelinePost>($"timelines/{generator(1)}/posts", CreateMarkdownPostRequest("[aaa](1) "));
+
+ var res = await client.GetAsync($"timelines/{generator(1)}/posts/{post.Id}/data");
+ var markdown = await res.Content.ReadAsStringAsync();
+
+ markdown.Should().MatchRegex(@$"\[aaa\]\(https?://.*/timelines/{generator(1)}/posts/{post.Id}/data/1\)");
+ markdown.Should().MatchRegex(@$"\[bbb\]\(https?://.*/timelines/{generator(1)}/posts/{post.Id}/data/2\)");
+ }
}
}
diff --git a/BackEnd/Timeline.Tests/packages.lock.json b/BackEnd/Timeline.Tests/packages.lock.json index 50b90c3c..bdcfaf35 100644 --- a/BackEnd/Timeline.Tests/packages.lock.json +++ b/BackEnd/Timeline.Tests/packages.lock.json @@ -127,6 +127,11 @@ "System.Xml.XmlDocument": "4.3.0"
}
},
+ "Markdig": {
+ "type": "Transitive",
+ "resolved": "0.23.0",
+ "contentHash": "jPPcnHGSDSedPvwZ6jiMJpvK3iJGA2djU6TFmEr6XK2BiYK1ier2lTHVwDt41XLxDbfGu5Dn42hKDzwqs049PA=="
+ },
"Microsoft.AspNetCore.Authorization": {
"type": "Transitive",
"resolved": "1.0.3",
@@ -1981,6 +1986,7 @@ "dependencies": {
"AutoMapper": "10.1.1",
"AutoMapper.Extensions.Microsoft.DependencyInjection": "8.1.0",
+ "Markdig": "0.23.0",
"Microsoft.AspNetCore.SpaServices.Extensions": "5.0.0",
"Microsoft.EntityFrameworkCore": "5.0.0",
"Microsoft.EntityFrameworkCore.Analyzers": "5.0.0",
diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index 4026d551..86c5c8cf 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -32,14 +32,17 @@ namespace Timeline.Controllers private readonly TimelineMapper _timelineMapper;
+ private readonly MarkdownProcessor _markdownProcessor;
+
/// <summary>
///
/// </summary>
- public TimelinePostController(ITimelineService timelineService, ITimelinePostService timelinePostService, TimelineMapper timelineMapper)
+ public TimelinePostController(ITimelineService timelineService, ITimelinePostService timelinePostService, TimelineMapper timelineMapper, MarkdownProcessor markdownProcessor)
{
_timelineService = timelineService;
_postService = timelinePostService;
_timelineMapper = timelineMapper;
+ _markdownProcessor = markdownProcessor;
}
private bool UserHasAllTimelineManagementPermission => this.UserHasPermission(UserPermission.AllTimelineManagement);
@@ -147,7 +150,15 @@ namespace Timeline.Controllers return await DataCacheHelper.GenerateActionResult(this,
() => _postService.GetPostDataDigest(timelineId, post, dataIndex),
- () => _postService.GetPostData(timelineId, post, dataIndex)
+ async () =>
+ {
+ var data = await _postService.GetPostData(timelineId, post, dataIndex);
+ if (data.ContentType == MimeTypes.TextMarkdown)
+ {
+ return new ByteData(_markdownProcessor.Process(data.Data, Url, timeline, post), data.ContentType);
+ }
+ return data;
+ }
);
}
diff --git a/BackEnd/Timeline/Services/MarkdownProcessor.cs b/BackEnd/Timeline/Services/MarkdownProcessor.cs new file mode 100644 index 00000000..f34432cd --- /dev/null +++ b/BackEnd/Timeline/Services/MarkdownProcessor.cs @@ -0,0 +1,52 @@ +using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Markdig;
+using Markdig.Renderers.Normalize;
+using Markdig.Syntax;
+using Markdig.Syntax.Inlines;
+using Microsoft.AspNetCore.Mvc;
+using Timeline.Controllers;
+
+namespace Timeline.Services
+{
+ public class MarkdownProcessor
+ {
+ public string Process(string text, Func<long, string> urlGenerator)
+ {
+ MarkdownDocument markdown = Markdown.Parse(text);
+ foreach (var link in markdown.Descendants().Where(e => e is LinkInline).Cast<LinkInline>())
+ {
+ if (int.TryParse(link.Url, out var dataIndex))
+ {
+ link.Url = urlGenerator(dataIndex);
+ }
+ }
+
+ var writer = new StringWriter();
+ NormalizeRenderer renderer = new NormalizeRenderer(writer);
+ renderer.Render(markdown);
+
+ return writer.ToString();
+ }
+
+ /// <summary>Convert data url to true url with post id.</summary>
+ public string Process(string text, IUrlHelper url, string timeline, long post)
+ {
+ return Process(
+ text,
+ dataIndex => url.ActionLink(
+ nameof(TimelinePostController.DataGet),
+ nameof(TimelinePostController)[0..^nameof(Controller).Length],
+ new { timeline, post, data_index = dataIndex }
+ )
+ );
+ }
+
+ public byte[] Process(byte[] data, IUrlHelper url, string timeline, long post)
+ {
+ return Encoding.UTF8.GetBytes(Process(Encoding.UTF8.GetString(data), url, timeline, post));
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Startup.cs b/BackEnd/Timeline/Startup.cs index 26ba3bfc..4f392b2d 100644 --- a/BackEnd/Timeline/Startup.cs +++ b/BackEnd/Timeline/Startup.cs @@ -125,6 +125,8 @@ namespace Timeline services.AddScoped<ISearchService, SearchService>();
+ services.AddScoped<MarkdownProcessor>();
+
services.AddOpenApiDocs();
if (_frontEndMode == FrontEndMode.Mock)
diff --git a/BackEnd/Timeline/Timeline.csproj b/BackEnd/Timeline/Timeline.csproj index 70536e00..6b565598 100644 --- a/BackEnd/Timeline/Timeline.csproj +++ b/BackEnd/Timeline/Timeline.csproj @@ -33,6 +33,7 @@ <ItemGroup>
<PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
+ <PackageReference Include="Markdig" Version="0.23.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.1">
<PrivateAssets>all</PrivateAssets>
diff --git a/BackEnd/Timeline/packages.lock.json b/BackEnd/Timeline/packages.lock.json index 36442da7..da61aafc 100644 --- a/BackEnd/Timeline/packages.lock.json +++ b/BackEnd/Timeline/packages.lock.json @@ -23,6 +23,12 @@ "Microsoft.Extensions.Options": "3.0.0"
}
},
+ "Markdig": {
+ "type": "Direct",
+ "requested": "[0.23.0, )",
+ "resolved": "0.23.0",
+ "contentHash": "jPPcnHGSDSedPvwZ6jiMJpvK3iJGA2djU6TFmEr6XK2BiYK1ier2lTHVwDt41XLxDbfGu5Dn42hKDzwqs049PA=="
+ },
"Microsoft.AspNetCore.SpaServices.Extensions": {
"type": "Direct",
"requested": "[5.0.0, )",
|