@using Microsoft.AspNetCore.Components.Web @using Microsoft.EntityFrameworkCore @using OpenArchival.Blazor.AdminPages @using OpenArchival.DataAccess @using OpenArchival.Blazor.CustomComponents @using MudExRichTextEditor @using MudBlazor @using System.Text @page "/admin/blogedit" @page "/admin/blogedit/{Id}" @layout AdminPages.AdminControlPanelLayout; Create a Blog Post @((MarkupString)BlogPostModel.Content) Publish @inject IDbContextFactory ContextFactory; @inject ISnackbar Snackbar; @inject NavigationManager NavigationManager; @*OnKeyDown="@(ev => HandleChipContainerEnter(ev, _tagsChipContainer, _tagsInputValue, () => _tagsInputValue = string.Empty))"*@ @code { [Parameter] public int Id { get; set; } public List StringTags { get; set; } = []; public BlogPost BlogPostModel { get; set; } = new(); private MudExRichTextEdit _contentEditor = default!; private string _tagsInputValue = ""; private ChipContainer _tagsChipContainer = default!; protected override void OnParametersSet() { if (Id != 0) { using var context = ContextFactory.CreateDbContext(); BlogPost? existingPost = context.BlogPosts.Include(p => p.Tags).Where(p => p.Id == Id).FirstOrDefault(); if (existingPost is null) { NavigationManager.NavigateTo($"blog-not-found/{System.Web.HttpUtility.UrlEncode($"No blog with id {Id} exists in the database!")}"); return; } BlogPostModel = existingPost; } base.OnParametersSet(); } private async Task DeDuplicatePostTags(BlogPost post, ApplicationDbContext context) { List finalTags = []; foreach (BlogPostTag tag in post.Tags) { var existing = await context.BlogPostTags.Where(t => t.Name == tag.Name).FirstOrDefaultAsync(); if (existing is not null) { finalTags.Add(existing); } else { context.BlogPostTags.Add(tag); finalTags.Add(tag); } } post.Tags = finalTags; } private void BuildBlogSearchIndex(BlogPost post) { var tagsSb = new StringBuilder(); var allSb = new StringBuilder(); allSb.Append($"{post.Title} "); allSb.Append($"{post.Content} "); foreach (BlogPostTag tag in post.Tags) { tagsSb.Append($"{tag.Name} "); allSb.Append($"{tag.Name} "); } post.AllSearchString = allSb.ToString(); post.TagsSearchString = tagsSb.ToString(); } private async Task OnPublishBlogPost(Microsoft.AspNetCore.Components.Web.MouseEventArgs args) { if (string.IsNullOrEmpty(BlogPostModel.Content)) { Snackbar.Add("Content is required in the blog post, write something.", Severity.Warning); return; } if (string.IsNullOrEmpty(BlogPostModel.Title)) { Snackbar.Add("A post title is required", Severity.Warning); return; } await using var context = await ContextFactory.CreateDbContextAsync(); BlogPostModel.ModifiedTime = DateTime.UtcNow; // Blog post does not exist in database if (BlogPostModel.Id == 0) { BlogPostModel.CreationTime = DateTime.UtcNow; // Loop through the tags and de-duplicate any of them await DeDuplicatePostTags(BlogPostModel, context); BuildBlogSearchIndex(BlogPostModel); context.BlogPosts.Add(BlogPostModel); } else { // Blog post exists in database // Find the existing post so we can update it BlogPost? existing = await context.BlogPosts.Include(p=>p.Tags).FirstOrDefaultAsync(p => p.Id == BlogPostModel.Id); if (existing is null) { Snackbar.Add($"Unable to find a post with id {BlogPostModel.Id} in the database, cannot update post!", Severity.Error); return; } // De-duplicate tags await DeDuplicatePostTags(BlogPostModel, context); // Copy over the values we want existing.Title = BlogPostModel.Title; existing.Content = BlogPostModel.Content; existing.ModifiedTime = BlogPostModel.ModifiedTime; existing.Tags.Clear(); foreach (var tag in BlogPostModel.Tags) { existing.Tags.Add(tag); } BuildBlogSearchIndex(existing); } await context.SaveChangesAsync(); Snackbar.Add("Changes saved!", Severity.Success); // Reset the model BlogPostModel = new(); StateHasChanged(); } public void HandleTagsEnter(KeyboardEventArgs args) { if (args.Key == "Enter") { var newTag = new BlogPostTag() { Name = _tagsInputValue }; _tagsInputValue = ""; BlogPostModel.Tags.Add(newTag); StateHasChanged(); } } }