Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v14.12.0 #838

Merged
merged 52 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
40afe23
Add server-side handling for color scheme preference
EdiWang Oct 9, 2024
5b4b99e
Update version numbers in Directory.Build.props
EdiWang Oct 9, 2024
46566be
Enable config-based dark mode and improve code readability
EdiWang Oct 9, 2024
b151bc2
Update PrefersColorScheme feature and configuration
EdiWang Oct 9, 2024
23b78ac
Update config key for PrefersColorScheme header name
EdiWang Oct 9, 2024
967dd52
Add DI, anti-forgery token, and "Index Now" settings
EdiWang Oct 10, 2024
487b933
Update icons for EnableWebmention and EnablePingback settings
EdiWang Oct 10, 2024
a45b150
Update webapp-prod.yml
EdiWang Oct 11, 2024
7d062b7
Update appsettings.json
EdiWang Oct 13, 2024
5aaee31
Ensure consistent timestamps in post commands
EdiWang Oct 13, 2024
e0b6472
Add LastModifiedUtc property and cooldown for IndexNow
EdiWang Oct 13, 2024
d5aafdd
Merge pull request #828 from EdiWang/dev/indexnow-cooldown
EdiWang Oct 13, 2024
d093ac5
Update package versions in project files
EdiWang Oct 14, 2024
b8f3ba5
Fix checkbox attribute and add unpublish button
EdiWang Oct 14, 2024
c05f9b6
Add localization for "Unpublish this post" in multiple languages
EdiWang Oct 14, 2024
cbb3832
Add modal confirmation for unpublishing posts
EdiWang Oct 14, 2024
26edf7b
Add new localization entries for multiple languages
EdiWang Oct 14, 2024
cf36989
Add feature to unpublish posts in Moonglade app
EdiWang Oct 14, 2024
9b7cd37
Enhance "Unpublish" modal functionality
EdiWang Oct 14, 2024
0af503c
Merge pull request #829 from EdiWang/feature/unpublish-posts
EdiWang Oct 14, 2024
286f3c9
Add Japanese reading time calculation to calculateReadingTime
EdiWang Oct 14, 2024
37dbea7
Update version to 14.12.0-preview.2
EdiWang Oct 14, 2024
12241c8
lazy load sign in page captcha code #830
EdiWang Oct 17, 2024
85df6ae
lazy load comment captcha #830
EdiWang Oct 17, 2024
d0bfbbb
Update README.md
EdiWang Oct 19, 2024
f9d09e8
Add "Experimental" section to appsettings.json
EdiWang Oct 21, 2024
f7934fa
Create SocialLink.cs
EdiWang Oct 21, 2024
358ed45
Create GetAllSocialLinksQuery.cs
EdiWang Oct 21, 2024
1fe159a
Update GetAllSocialLinksQuery.cs
EdiWang Oct 21, 2024
dbcb7f8
Create SocialLinkViewComponent.cs
EdiWang Oct 21, 2024
2996dd5
Create Default.cshtml
EdiWang Oct 21, 2024
ba26d64
Update _Aside.cshtml
EdiWang Oct 21, 2024
673c31a
Update _Aside.cshtml
EdiWang Oct 21, 2024
0b745cf
Merge pull request #835 from EdiWang/feature/social-links
EdiWang Oct 21, 2024
3a9930e
Fix umlaut display issue by decoding HTML entities
EdiWang Oct 21, 2024
6e3201c
Decode ContentAbstract to fix old data
EdiWang Oct 21, 2024
ff7d415
Merge pull request #836 from EdiWang/fix/umlauts-encoding
EdiWang Oct 21, 2024
125a6e3
code clean up
EdiWang Oct 21, 2024
8861e86
bump version
EdiWang Oct 21, 2024
ccb84be
Update README.md
EdiWang Oct 22, 2024
356e165
Update Npgsql.EntityFrameworkCore.PostgreSQL to 8.0.10
EdiWang Oct 22, 2024
5ba5b5b
Add SocialLinkSettings to BlogConfig and initialization
EdiWang Oct 22, 2024
0074982
Add POST endpoint for updating social link settings
EdiWang Oct 22, 2024
ec4a6b3
Refactor social links config to use IBlogConfig
EdiWang Oct 22, 2024
2e0ded0
Add Social Links management page and settings model
EdiWang Oct 22, 2024
ace486e
Refactor SocialLink handling to use arrays instead of lists
EdiWang Oct 22, 2024
ed533d1
Enhance UI layout and admin toolbar
EdiWang Oct 22, 2024
8b97446
Add new properties and update translations
EdiWang Oct 22, 2024
a15eeed
Merge pull request #837 from EdiWang/feature/social-links-in-db
EdiWang Oct 22, 2024
2eeea55
Update version tag to 14.12.0-rc.1 in Directory.Build.props
EdiWang Oct 24, 2024
0246e61
Remove DotNetVersion property from WriteResponse method
EdiWang Oct 25, 2024
1cc20e2
Update version to 14.12.0 final release
EdiWang Oct 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/webapp-prod.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Azure Web App (PROD)

env:
AZURE_WEBAPP_NAME: moonglade-ediwang-us
AZURE_WEBAPP_NAME: ediwang
AZURE_WEBAPP_PACKAGE_PATH: '.'
DOTNET_VERSION: '8'

Expand Down Expand Up @@ -66,5 +66,5 @@ jobs:
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
clean: true
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE2 }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A personal blog system that optimized for [**Microsoft Azure**](https://azure.mi

This is the way https://edi.wang is deployed, by taking advantage of as many Azure services as possible, the blog can run very fast and secure. There is no automated script to deploy it, you need to manually create all the resources.

![image](https://cdn.edi.wang/web-assets/ediwang-azure-arch-visio-nov2022.png)
![image](https://cdn.edi.wang/web-assets/ediwang-azure-arch-visio-oct2024.svg)

### Quick Deploy on Azure (App Service on Linux)

Expand Down
6 changes: 3 additions & 3 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<Authors>Edi Wang</Authors>
<Company>edi.wang</Company>
<Copyright>(C) 2024 [email protected]</Copyright>
<AssemblyVersion>14.11.0.0</AssemblyVersion>
<FileVersion>14.11.0.0</FileVersion>
<Version>14.11.0</Version>
<AssemblyVersion>14.12.0.0</AssemblyVersion>
<FileVersion>14.12.0.0</FileVersion>
<Version>14.12.0</Version>
</PropertyGroup>
</Project>
4 changes: 4 additions & 0 deletions src/Moonglade.Configuration/BlogConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface IBlogConfig
CustomStyleSheetSettings CustomStyleSheetSettings { get; set; }
CustomMenuSettings CustomMenuSettings { get; set; }
LocalAccountSettings LocalAccountSettings { get; set; }
SocialLinkSettings SocialLinkSettings { get; set; }
SystemManifestSettings SystemManifestSettings { get; set; }

IEnumerable<int> LoadFromConfig(IDictionary<string, string> config);
Expand All @@ -40,6 +41,8 @@ public class BlogConfig : IBlogConfig

public LocalAccountSettings LocalAccountSettings { get; set; }

public SocialLinkSettings SocialLinkSettings { get; set; }

public SystemManifestSettings SystemManifestSettings { get; set; }

public IEnumerable<int> LoadFromConfig(IDictionary<string, string> config)
Expand All @@ -53,6 +56,7 @@ public IEnumerable<int> LoadFromConfig(IDictionary<string, string> config)
CustomStyleSheetSettings = AssignValueForConfigItem(7, CustomStyleSheetSettings.DefaultValue, config);
CustomMenuSettings = AssignValueForConfigItem(10, CustomMenuSettings.DefaultValue, config);
LocalAccountSettings = AssignValueForConfigItem(11, LocalAccountSettings.DefaultValue, config);
SocialLinkSettings = AssignValueForConfigItem(12, SocialLinkSettings.DefaultValue, config);

// Special case
SystemManifestSettings = AssignValueForConfigItem(99, SystemManifestSettings.DefaultValue, config);
Expand Down
35 changes: 35 additions & 0 deletions src/Moonglade.Configuration/SocialLink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;

namespace Moonglade.Configuration;

public class SocialLinkSettings : IBlogSettings
{
public bool IsEnabled { get; set; }

public SocialLink[] Links { get; set; } = [];

public static SocialLinkSettings DefaultValue =>
new()
{
IsEnabled = false,
Links = []
};
}

public class SocialLink
{
public string Name { get; set; }

public string Icon { get; set; }

public string Url { get; set; }
}

public class SocialLinkSettingsJsonModel
{
[Display(Name = "Enable Social Links")]
public bool IsEnabled { get; set; }

[MaxLength(1024)]
public string JsonData { get; set; }
}
21 changes: 21 additions & 0 deletions src/Moonglade.Core/GetAllSocialLinksQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Moonglade.Configuration;

namespace Moonglade.Core;

public record GetAllSocialLinksQuery : IRequest<SocialLink[]>;

public class GetAllSocialLinksQueryHandler(IBlogConfig blogConfig) : IRequestHandler<GetAllSocialLinksQuery, SocialLink[]>
{
public Task<SocialLink[]> Handle(GetAllSocialLinksQuery request, CancellationToken ct)
{
var section = blogConfig.SocialLinkSettings;

if (!section.IsEnabled)
{
return Task.FromResult(Array.Empty<SocialLink>());
}

var links = blogConfig.SocialLinkSettings.Links;
return Task.FromResult(links);
}
}
7 changes: 4 additions & 3 deletions src/Moonglade.Core/PostFeature/CreatePostCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,21 @@ public async Task<PostEntity> Handle(CreatePostCommand request, CancellationToke
abs = request.Payload.Abstract.Trim();
}

var utcNow = DateTime.UtcNow;
var post = new PostEntity
{
CommentEnabled = request.Payload.EnableComment,
Id = Guid.NewGuid(),
PostContent = request.Payload.EditorContent,
ContentAbstract = abs,
CreateTimeUtc = DateTime.UtcNow,
LastModifiedUtc = DateTime.UtcNow, // Fix draft orders
CreateTimeUtc = utcNow,
LastModifiedUtc = utcNow, // Fix draft orders
Slug = request.Payload.Slug.ToLower().Trim(),
Author = request.Payload.Author?.Trim(),
Title = request.Payload.Title.Trim(),
ContentLanguageCode = request.Payload.LanguageCode,
IsFeedIncluded = request.Payload.FeedIncluded,
PubDateUtc = request.Payload.IsPublished ? DateTime.UtcNow : null,
PubDateUtc = request.Payload.IsPublished ? utcNow : null,
IsDeleted = false,
IsPublished = request.Payload.IsPublished,
IsFeatured = request.Payload.Featured,
Expand Down
3 changes: 3 additions & 0 deletions src/Moonglade.Core/PostFeature/PostEditModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,7 @@ public class PostEditModel
public bool IsOutdated { get; set; }

public bool WarnSlugModification => PublishDate.HasValue && (DateTime.UtcNow - PublishDate.Value).Days > 3;

[HiddenInput]
public string LastModifiedUtc { get; set; }
}
24 changes: 24 additions & 0 deletions src/Moonglade.Core/PostFeature/UnpublishPostCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Edi.CacheAside.InMemory;
using Moonglade.Data;

namespace Moonglade.Core.PostFeature;

public record UnpublishPostCommand(Guid Id) : IRequest;

public class UnpublishPostCommandHandler(MoongladeRepository<PostEntity> repo, ICacheAside cache) : IRequestHandler<UnpublishPostCommand>
{
public async Task Handle(UnpublishPostCommand request, CancellationToken ct)
{
var post = await repo.GetByIdAsync(request.Id, ct);
if (null == post) return;

post.IsPublished = false;
post.PubDateUtc = null;
post.RouteLink = null;
post.LastModifiedUtc = DateTime.UtcNow;

await repo.UpdateAsync(post, ct);

cache.Remove(BlogCachePartition.Post.ToString(), request.Id.ToString());
}
}
5 changes: 3 additions & 2 deletions src/Moonglade.Core/PostFeature/UpdatePostCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public UpdatePostCommandHandler(

public async Task<PostEntity> Handle(UpdatePostCommand request, CancellationToken ct)
{
var utcNow = DateTime.UtcNow;
var (guid, postEditModel) = request;
var post = await _postRepo.GetByIdAsync(guid, ct);
if (null == post)
Expand All @@ -73,7 +74,7 @@ public async Task<PostEntity> Handle(UpdatePostCommand request, CancellationToke
if (postEditModel.IsPublished && !post.IsPublished)
{
post.IsPublished = true;
post.PubDateUtc = DateTime.UtcNow;
post.PubDateUtc = utcNow;
}

// #325: Allow changing publish date for published posts
Expand All @@ -87,7 +88,7 @@ public async Task<PostEntity> Handle(UpdatePostCommand request, CancellationToke
post.Author = postEditModel.Author?.Trim();
post.Slug = postEditModel.Slug.ToLower().Trim();
post.Title = postEditModel.Title.Trim();
post.LastModifiedUtc = DateTime.UtcNow;
post.LastModifiedUtc = utcNow;
post.IsFeedIncluded = postEditModel.FeedIncluded;
post.ContentLanguageCode = postEditModel.LanguageCode;
post.IsFeatured = postEditModel.Featured;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.8" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Moonglade.Data\Moonglade.Data.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion src/Moonglade.ImageStorage/Moonglade.ImageStorage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.22.1" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.22.2" />
<PackageReference Include="Minio" Version="6.0.3" />
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions src/Moonglade.Setup/BlogConfigInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ await mediator.Send(new AddDefaultConfigurationCommand(key, nameof(CustomMenuSet
await mediator.Send(new AddDefaultConfigurationCommand(key, nameof(LocalAccountSettings),
LocalAccountSettings.DefaultValue.ToJson()));
break;
case 12:
await mediator.Send(new AddDefaultConfigurationCommand(key, nameof(SocialLinkSettings),
SocialLinkSettings.DefaultValue.ToJson()));
break;
case 99:
await mediator.Send(new AddDefaultConfigurationCommand(key, nameof(SystemManifestSettings),
isNew ?
Expand Down
7 changes: 6 additions & 1 deletion src/Moonglade.Utils/ContentProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Markdig;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml.Linq;

namespace Moonglade.Utils;
Expand All @@ -26,10 +27,14 @@ public static string GetPostAbstract(string content, int wordCount, bool useMark
MarkdownToContent(content, MarkdownConvertType.Text) :
RemoveTags(content);

var result = plainText.Ellipsize(wordCount);
var decodedText = HtmlDecode(plainText);
var result = decodedText.Ellipsize(wordCount);
return result;
}

// Fix #833 - umlauts like (ä,ö,ü). are not displayed correctly in the abstract
public static string HtmlDecode(string content) => HttpUtility.HtmlDecode(content);

public static string RemoveTags(string html)
{
if (string.IsNullOrEmpty(html))
Expand Down
1 change: 0 additions & 1 deletion src/Moonglade.Web/Configuration/ConfigureEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public static Task WriteResponse(HttpContext context, HealthReport result)
var obj = new
{
Helper.AppVersion,
DotNetVersion = Environment.Version.ToString(),
EnvironmentTags = Helper.GetEnvironmentTags(),
GeoMatch = context.Request.Headers["x-geo-match"]
};
Expand Down
25 changes: 24 additions & 1 deletion src/Moonglade.Web/Controllers/PostController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Moonglade.Web.Controllers;
[ApiController]
[Route("api/[controller]")]
public class PostController(
IConfiguration configuration,
IMediator mediator,
IBlogConfig blogConfig,
ITimeZoneResolver timeZoneResolver,
Expand Down Expand Up @@ -61,7 +62,20 @@ await mediator.Send(new CreatePostCommand(model)) :
cannonService.FireAsync<IWebmentionSender>(async sender => await sender.SendWebmentionAsync(link.ToString(), postEntity.PostContent));
}

cannonService.FireAsync<IIndexNowClient>(async sender => await sender.SendRequestAsync(link));
var isNewPublish = postEntity.LastModifiedUtc == postEntity.PubDateUtc;

bool indexCoolDown = true;
var minimalIntervalMinutes = int.Parse(configuration["IndexNow:MinimalIntervalMinutes"]!);
if (!string.IsNullOrWhiteSpace(model.LastModifiedUtc))
{
var lastSavedInterval = DateTime.Parse(model.LastModifiedUtc) - DateTime.UtcNow;
indexCoolDown = lastSavedInterval.TotalMinutes > minimalIntervalMinutes;
}

if (isNewPublish || indexCoolDown)
{
cannonService.FireAsync<IIndexNowClient>(async sender => await sender.SendRequestAsync(link));
}
}

return Ok(new { PostId = postEntity.Id });
Expand Down Expand Up @@ -117,6 +131,15 @@ public async Task<IActionResult> EmptyRecycleBin()
return NoContent();
}

[TypeFilter(typeof(ClearBlogCache), Arguments = [BlogCacheType.Subscription | BlogCacheType.SiteMap])]
[HttpPut("{postId:guid}/unpublish")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Unpublish([NotEmpty] Guid postId)
{
await mediator.Send(new UnpublishPostCommand(postId));
return NoContent();
}

[IgnoreAntiforgeryToken]
[HttpPost("keep-alive")]
[ProducesResponseType(StatusCodes.Status200OK)]
Expand Down
20 changes: 20 additions & 0 deletions src/Moonglade.Web/Controllers/SettingsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@ public async Task<IActionResult> Advanced(AdvancedSettings model)
return NoContent();
}

[HttpPost("social-link")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> SocialLink(SocialLinkSettingsJsonModel model)
{
if (model.IsEnabled && string.IsNullOrWhiteSpace(model.JsonData))
{
ModelState.AddModelError(nameof(SocialLinkSettingsJsonModel.JsonData), "JsonData is required");
return BadRequest(ModelState.CombineErrorMessages());
}

blogConfig.SocialLinkSettings = new()
{
IsEnabled = model.IsEnabled,
Links = model.JsonData.FromJson<SocialLink[]>()
};

await SaveConfigAsync(blogConfig.SocialLinkSettings);
return NoContent();
}

[HttpPost("reset")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Reset(BlogDbContext context, IHostApplicationLifetime applicationLifetime)
Expand Down
14 changes: 10 additions & 4 deletions src/Moonglade.Web/Middleware/PrefersColorSchemeMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

public class PrefersColorSchemeMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
public async Task InvokeAsync(HttpContext context, IConfiguration configuration)
{
var headerName = configuration["PrefersColorSchemeHeader:HeaderName"];
if (string.IsNullOrWhiteSpace(headerName))
{
await next(context);
}

context.Response.OnStarting(() =>
{
context.Response.Headers["Accept-CH"] = "Sec-CH-Prefers-Color-Scheme";
context.Response.Headers["Vary"] = "Sec-CH-Prefers-Color-Scheme";
context.Response.Headers["Critical-CH"] = "Sec-CH-Prefers-Color-Scheme";
context.Response.Headers["Accept-CH"] = headerName;
context.Response.Headers["Vary"] = headerName;
context.Response.Headers["Critical-CH"] = headerName;
return Task.CompletedTask;
});

Expand Down
2 changes: 1 addition & 1 deletion src/Moonglade.Web/Moonglade.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<PackageReference Include="Edi.PasswordGenerator" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="8.0.10" />

<PackageReference Include="TinyMCE" Version="7.3.0" />
<PackageReference Include="TinyMCE" Version="7.4.1" />
<PackageReference Include="Moonglade.MonacoEditor" Version="0.50.0.1002" />
</ItemGroup>
<ItemGroup>
Expand Down
Loading