Improved article body formatting
This commit is contained in:
parent
e816b9fb43
commit
e1cab9b53f
|
@ -188,24 +188,13 @@
|
||||||
Article.PublishDate = Model.PublishDate.Value;
|
Article.PublishDate = Model.PublishDate.Value;
|
||||||
if (Article.Status is ArticleStatus.Published && Article.PublishDate < DateTimeOffset.Now) {
|
if (Article.Status is ArticleStatus.Published && Article.PublishDate < DateTimeOffset.Now) {
|
||||||
// can't change slugs when the article is public
|
// can't change slugs when the article is public
|
||||||
} else if (!string.IsNullOrWhiteSpace(Model.Slug) || string.IsNullOrWhiteSpace(Article.Slug)) {
|
} else {
|
||||||
string baseSlug = Model.Slug ?? Article.Title;
|
Article.UpdateSlug(Model.Slug);
|
||||||
baseSlug = baseSlug.ToLowerInvariant()[..Math.Min(64, baseSlug.Length)];
|
|
||||||
string slug = Uri.EscapeDataString(baseSlug).Replace("-", "+").Replace("%20", "-");
|
|
||||||
// if our escaping increases the slug length, there is a chance it ends with an escape
|
|
||||||
// character, so if this overshoot is not divisible by 3, then we risk cutting of the
|
|
||||||
// escape character, so we need to remove it in it's entirely if that's the case
|
|
||||||
int escapeTrimOvershoot = Math.Max(0, 3 - (slug.Length - baseSlug.Length) % 3);
|
|
||||||
// if the slug already fits 64 character, there will be no cutoff in the next operation anyway,
|
|
||||||
// so we don't need to fix what is described in the previous comment
|
|
||||||
if (slug.Length <= 64) escapeTrimOvershoot = 0;
|
|
||||||
Article.Slug = slug[..Math.Min(slug.Length, 64 - escapeTrimOvershoot)];
|
|
||||||
Model.Slug = Article.Slug;
|
Model.Slug = Article.Slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
Article.LastModified = DateTimeOffset.UtcNow;
|
Article.LastModified = DateTimeOffset.UtcNow;
|
||||||
Article.BodyHtml = MarkdownUtilities.Parse(Article.Body);
|
Article.UpdateBody();
|
||||||
Article.BodyPlain = HtmlUtilities.GetPlainText(Article.BodyHtml);
|
|
||||||
|
|
||||||
await using var context = await ContextFactory.CreateDbContextAsync();
|
await using var context = await ContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,69 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Wave.Utilities;
|
||||||
|
|
||||||
namespace Wave.Data;
|
namespace Wave.Data;
|
||||||
|
|
||||||
public enum ArticleStatus {
|
public enum ArticleStatus {
|
||||||
Draft = 0,
|
Draft = 0,
|
||||||
InReview = 1,
|
InReview = 1,
|
||||||
Published = 2
|
Published = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:: Add tags for MVP ?
|
// TODO:: Add tags for MVP ?
|
||||||
// TODO:: Archive System (Notice / Redirect to new content?) (Deprecation date?)
|
// TODO:: Archive System (Notice / Redirect to new content?) (Deprecation date?)
|
||||||
|
|
||||||
public class Article : ISoftDelete {
|
public class Article : ISoftDelete {
|
||||||
[Key]
|
[Key]
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
|
|
||||||
// Computed
|
// Computed
|
||||||
public bool CanBePublic { get; set; }
|
public bool CanBePublic { get; set; }
|
||||||
|
|
||||||
[MaxLength(256)]
|
[MaxLength(256)]
|
||||||
public required string Title { get; set; }
|
public required string Title { get; set; }
|
||||||
public required string Body { get; set; }
|
// ReSharper disable thrice EntityFramework.ModelValidation.UnlimitedStringLength
|
||||||
public string BodyHtml { get; set; } = string.Empty;
|
public required string Body { get; set; }
|
||||||
public string BodyPlain { get; set; } = string.Empty;
|
public string BodyHtml { get; set; } = string.Empty;
|
||||||
|
public string BodyPlain { get; set; } = string.Empty;
|
||||||
|
|
||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
public string Slug { get; set; } = string.Empty;
|
public string Slug { get; set; } = string.Empty;
|
||||||
|
|
||||||
public required ApplicationUser Author { get; set; }
|
public required ApplicationUser Author { get; set; }
|
||||||
public ApplicationUser? Reviewer { get; set; }
|
public ApplicationUser? Reviewer { get; set; }
|
||||||
|
|
||||||
public ArticleStatus Status { get; set; }
|
public ArticleStatus Status { get; set; }
|
||||||
public DateTimeOffset CreationDate { get; set; } = DateTimeOffset.Now;
|
public DateTimeOffset CreationDate { get; set; } = DateTimeOffset.Now;
|
||||||
public DateTimeOffset PublishDate { get; set; } = DateTimeOffset.MaxValue;
|
public DateTimeOffset PublishDate { get; set; } = DateTimeOffset.MaxValue;
|
||||||
public DateTimeOffset? LastModified { get; set; }
|
public DateTimeOffset? LastModified { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns LastModified if it's after the articles PublishDate, otherwise gives you the PublishDate
|
/// Returns LastModified if it's after the articles PublishDate, otherwise gives you the PublishDate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset LastPublicChange => LastModified > PublishDate ? LastModified.Value : PublishDate;
|
public DateTimeOffset LastPublicChange => LastModified > PublishDate ? LastModified.Value : PublishDate;
|
||||||
|
|
||||||
public IList<Category> Categories { get; } = [];
|
public IList<Category> Categories { get; } = [];
|
||||||
public IList<ArticleImage> Images { get; } = [];
|
public IList<ArticleImage> Images { get; } = [];
|
||||||
|
|
||||||
|
public void UpdateSlug(string? potentialNewSlug) {
|
||||||
|
if (string.IsNullOrWhiteSpace(potentialNewSlug) && !string.IsNullOrWhiteSpace(Slug)) return;
|
||||||
|
|
||||||
|
string baseSlug = potentialNewSlug ?? Title;
|
||||||
|
baseSlug = baseSlug.ToLowerInvariant()[..Math.Min(64, baseSlug.Length)];
|
||||||
|
string slug = Uri.EscapeDataString(baseSlug).Replace("-", "+").Replace("%20", "-");
|
||||||
|
// if our escaping increases the slug length, there is a chance it ends with an escape
|
||||||
|
// character, so if this overshoot is not divisible by 3, then we risk cutting of the
|
||||||
|
// escape character, so we need to remove it in it's entirely if that's the case
|
||||||
|
int escapeTrimOvershoot = Math.Max(0, 3 - (slug.Length - baseSlug.Length) % 3);
|
||||||
|
// if the slug already fits 64 character, there will be no cutoff in the next operation anyway,
|
||||||
|
// so we don't need to fix what is described in the previous comment
|
||||||
|
if (slug.Length <= 64) escapeTrimOvershoot = 0;
|
||||||
|
Slug = slug[..Math.Min(slug.Length, 64 - escapeTrimOvershoot)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBody() {
|
||||||
|
BodyHtml = MarkdownUtilities.Parse(Body).Trim();
|
||||||
|
BodyPlain = HtmlUtilities.GetPlainText(BodyHtml).Trim();
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue