First cut at page add/edit
This commit is contained in:
		
							parent
							
								
									f8c58dbc3d
								
							
						
					
					
						commit
						d0cc9d0d7c
					
				| @ -33,6 +33,14 @@ public static class PageExtensions | |||||||
|     public static async Task<Page?> FindById(this DbSet<Page> db, string id) => |     public static async Task<Page?> FindById(this DbSet<Page> db, string id) => | ||||||
|         await db.SingleOrDefaultAsync(p => p.Id == id).ConfigureAwait(false); |         await db.SingleOrDefaultAsync(p => p.Id == id).ConfigureAwait(false); | ||||||
| 
 | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Retrieve a page by its ID, including its revisions (non-tracked) | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="id">The ID of the page to retrieve</param> | ||||||
|  |     /// <returns>The requested page (or null if it is not found)</returns> | ||||||
|  |     public static async Task<Page?> FindByIdWithRevisions(this DbSet<Page> db, string id) => | ||||||
|  |         await db.Include(p => p.Revisions).SingleOrDefaultAsync(p => p.Id == id).ConfigureAwait(false); | ||||||
|  | 
 | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Retrieve a page by its permalink (non-tracked) |     /// Retrieve a page by its permalink (non-tracked) | ||||||
|     /// </summary> |     /// </summary> | ||||||
| @ -40,4 +48,20 @@ public static class PageExtensions | |||||||
|     /// <returns>The requested page (or null if it is not found)</returns> |     /// <returns>The requested page (or null if it is not found)</returns> | ||||||
|     public static async Task<Page?> FindByPermalink(this DbSet<Page> db, string permalink) => |     public static async Task<Page?> FindByPermalink(this DbSet<Page> db, string permalink) => | ||||||
|         await db.SingleOrDefaultAsync(p => p.Permalink == permalink).ConfigureAwait(false); |         await db.SingleOrDefaultAsync(p => p.Permalink == permalink).ConfigureAwait(false); | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Retrieve a page of pages (non-tracked) | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="pageNbr">The page number to retrieve</param> | ||||||
|  |     /// <returns>The pages</returns> | ||||||
|  |     public static async Task<List<Page>> FindPageOfPages(this DbSet<Page> db, int pageNbr) => | ||||||
|  |         await db.Skip((pageNbr - 1) * 50).Take(25).ToListAsync().ConfigureAwait(false); | ||||||
|  |      | ||||||
|  |     /// <summary> | ||||||
|  |     /// Retrieve a page by its ID (tracked) | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="id">The ID of the page to retrieve</param> | ||||||
|  |     /// <returns>The requested page (or null if it is not found)</returns> | ||||||
|  |     public static async Task<Page?> GetById(this DbSet<Page> db, string id) => | ||||||
|  |         await db.AsTracking().Include(p => p.Revisions).SingleOrDefaultAsync(p => p.Id == id).ConfigureAwait(false); | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,8 +13,10 @@ | |||||||
|             @Resources.Published <span class="badge rounded-pill bg-secondary">@Model.Posts</span> |             @Resources.Published <span class="badge rounded-pill bg-secondary">@Model.Posts</span> | ||||||
|               @Resources.Drafts <span class="badge rounded-pill bg-secondary">@Model.Drafts</span> |               @Resources.Drafts <span class="badge rounded-pill bg-secondary">@Model.Drafts</span> | ||||||
|           </h6> |           </h6> | ||||||
|           <a asp-action="All" asp-controller="Post" class="btn btn-secondary me-2">View All</a> |           <a asp-action="All" asp-controller="Post" class="btn btn-secondary me-2">@Resources.ViewAll</a> | ||||||
|           <a asp-action="Edit" asp-controller="Post" asp-route-id="new" class="btn btn-primary">Write a New Post</a> |           <a asp-action="Edit" asp-controller="Post" asp-route-id="new" class="btn btn-primary"> | ||||||
|  |             @Resources.WriteANewPost | ||||||
|  |           </a> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </section> |     </section> | ||||||
| @ -26,8 +28,10 @@ | |||||||
|             @Resources.All <span class="badge rounded-pill bg-secondary">@Model.Pages</span> |             @Resources.All <span class="badge rounded-pill bg-secondary">@Model.Pages</span> | ||||||
|               @Resources.ShownInPageList <span class="badge rounded-pill bg-secondary">@Model.ListedPages</span> |               @Resources.ShownInPageList <span class="badge rounded-pill bg-secondary">@Model.ListedPages</span> | ||||||
|           </h6> |           </h6> | ||||||
|           <a asp-action="All" asp-controller="Page" class="btn btn-secondary me-2">View All</a> |           <a asp-action="All" asp-controller="Page" class="btn btn-secondary me-2">@Resources.ViewAll</a> | ||||||
|           <a asp-action="Edit" asp-controller="Page" asp-route-id="new" class="btn btn-primary">Create a New Page</a> |           <a asp-action="Edit" asp-controller="Page" asp-route-id="new" class="btn btn-primary"> | ||||||
|  |             @Resources.CreateANewPage | ||||||
|  |           </a> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </section> |     </section> | ||||||
| @ -41,9 +45,9 @@ | |||||||
|             @Resources.All <span class="badge rounded-pill bg-secondary">@Model.Categories</span> |             @Resources.All <span class="badge rounded-pill bg-secondary">@Model.Categories</span> | ||||||
|               @Resources.TopLevel <span class="badge rounded-pill bg-secondary">@Model.TopLevelCategories</span> |               @Resources.TopLevel <span class="badge rounded-pill bg-secondary">@Model.TopLevelCategories</span> | ||||||
|           </h6> |           </h6> | ||||||
|           <a asp-action="All" asp-controller="Category" class="btn btn-secondary me-2">View All</a> |           <a asp-action="All" asp-controller="Category" class="btn btn-secondary me-2">@Resources.ViewAll</a> | ||||||
|           <a asp-action="Edit" asp-controller="Category" asp-route-id="new" class="btn btn-secondary"> |           <a asp-action="Edit" asp-controller="Category" asp-route-id="new" class="btn btn-secondary"> | ||||||
|             Add a New Category |             @Resources.AddANewCategory | ||||||
|           </a> |           </a> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
| @ -51,7 +55,7 @@ | |||||||
|   </div> |   </div> | ||||||
|   <div class="row pb-3"> |   <div class="row pb-3"> | ||||||
|     <div class="col text-end"> |     <div class="col text-end"> | ||||||
|       <a asp-action="Settings" class="btn btn-secondary">Modify Settings</a> |       <a asp-action="Settings" class="btn btn-secondary">@Resources.ModifySettings</a> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| </article> | </article> | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| @model SettingsModel | @model SettingsModel | ||||||
| @{ | @{ | ||||||
|     Layout = "_AdminLayout"; |     Layout = "_AdminLayout"; | ||||||
|     ViewBag.Title = "Web Log Settings"; |     ViewBag.Title = Resources.WebLogSettings; | ||||||
| } | } | ||||||
| <article class="pt-3"> | <article class="pt-3"> | ||||||
|   <form asp-action="SaveSettings" method="post"> |   <form asp-action="SaveSettings" method="post"> | ||||||
|  | |||||||
							
								
								
									
										37
									
								
								src/MyWebLog/Features/Pages/All.cshtml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/MyWebLog/Features/Pages/All.cshtml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | @model PageListModel | ||||||
|  | @{ | ||||||
|  |     Layout = "_AdminLayout"; | ||||||
|  |     ViewBag.Title = Resources.Pages; | ||||||
|  | } | ||||||
|  | <article class="container"> | ||||||
|  |   <a asp-action="Edit" asp-route-id="new" class="btn btn-primary btn-sm my-3">@Resources.CreateANewPage</a> | ||||||
|  |   <table class="table table-sm table-striped table-hover"> | ||||||
|  |     <thead> | ||||||
|  |       <tr> | ||||||
|  |         <th scope="col">@Resources.Actions</th> | ||||||
|  |         <th scope="col">@Resources.Title</th> | ||||||
|  |         <th scope="col">@Resources.InListQuestion</th> | ||||||
|  |         <th scope="col">@Resources.LastUpdated</th> | ||||||
|  |       </tr> | ||||||
|  |     </thead> | ||||||
|  |     <tbody> | ||||||
|  |       @foreach (var pg in Model.Pages) | ||||||
|  |       { | ||||||
|  |         <tr> | ||||||
|  |           <td> | ||||||
|  |             <a asp-action="Edit" asp-route-id="@pg.Id">@Resources.Edit</a> | ||||||
|  |           </td> | ||||||
|  |           <td> | ||||||
|  |             @pg.Title | ||||||
|  |             @if (pg.Id == Model.WebLog.DefaultPage) | ||||||
|  |             { | ||||||
|  |               <text>   </text><span class="badge bg-success">HOME PAGE</span> | ||||||
|  |             } | ||||||
|  |           </td> | ||||||
|  |           <td><yes-no asp-for="pg.ShowInPageList" /></td> | ||||||
|  |           <td>@pg.UpdatedOn.ToString(Resources.DateFormatString)</td> | ||||||
|  |         </tr> | ||||||
|  |       } | ||||||
|  |     </tbody> | ||||||
|  |   </table> | ||||||
|  | </article> | ||||||
							
								
								
									
										56
									
								
								src/MyWebLog/Features/Pages/Edit.cshtml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/MyWebLog/Features/Pages/Edit.cshtml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | @model EditPageModel | ||||||
|  | @{ | ||||||
|  |     Layout = "_AdminLayout"; | ||||||
|  |     ViewBag.Title = Model.IsNew ? Resources.AddANewPage : Resources.EditPage; | ||||||
|  | } | ||||||
|  | <article> | ||||||
|  |   <h2 class="pb-3">@ViewBag.Title</h2> | ||||||
|  |   <form asp-action="Save" asp-route-id="@Model.PageId" method="post"> | ||||||
|  |     <input type="hidden" asp-for="PageId"> | ||||||
|  |     <div class="container"> | ||||||
|  |       <div class="row mb-3"> | ||||||
|  |         <div class="col"> | ||||||
|  |           <div class="form-floating"> | ||||||
|  |             <input type="text" asp-for="Title" class="form-control" autofocus> | ||||||
|  |             <label asp-for="Title"></label> | ||||||
|  |             <span asp-validation-for="Title"></span> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="row mb-3"> | ||||||
|  |         <div class="col-9"> | ||||||
|  |           <div class="form-floating"> | ||||||
|  |             <input type="text" asp-for="Permalink" class="form-control"> | ||||||
|  |             <label asp-for="Permalink"></label> | ||||||
|  |             <span asp-validation-for="Permalink"></span> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="col-3 align-self-center"> | ||||||
|  |           <div class="form-check form-switch"> | ||||||
|  |             <input type="checkbox" asp-for="IsShownInPageList" class="form-check-input"> | ||||||
|  |             <label asp-for="IsShownInPageList" class="form-check-label"></label> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="row mb-2"> | ||||||
|  |         <div class="col"> | ||||||
|  |           <label asp-for="Text"></label>     | ||||||
|  |           <input type="radio" asp-for="Source" id="source_html" class="btn-check" value="@RevisionSource.Html"> | ||||||
|  |           <label class="btn btn-sm btn-outline-secondary" for="source_html">HTML</label> | ||||||
|  |           <input type="radio" asp-for="Source" id="source_md" class="btn-check" value="@RevisionSource.Markdown"> | ||||||
|  |           <label class="btn btn-sm btn-outline-secondary" for="source_md">Markdown</label> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="row mb-3"> | ||||||
|  |         <div class="col"> | ||||||
|  |           <textarea asp-for="Text" class="form-control" rows="10"></textarea> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="row mb-3"> | ||||||
|  |         <div class="col"> | ||||||
|  |           <button type="submit" class="btn btn-primary">@Resources.SaveChanges</button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </form> | ||||||
|  | </article> | ||||||
							
								
								
									
										99
									
								
								src/MyWebLog/Features/Pages/EditPageModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/MyWebLog/Features/Pages/EditPageModel.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | |||||||
|  | using System.ComponentModel.DataAnnotations; | ||||||
|  | 
 | ||||||
|  | namespace MyWebLog.Features.Pages; | ||||||
|  | 
 | ||||||
|  | /// <summary> | ||||||
|  | /// Model used to edit pages | ||||||
|  | /// </summary> | ||||||
|  | public class EditPageModel : MyWebLogModel | ||||||
|  | { | ||||||
|  |     /// <summary> | ||||||
|  |     /// The ID of the page being edited | ||||||
|  |     /// </summary> | ||||||
|  |     public string PageId { get; set; } = "new"; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Whether this is a new page | ||||||
|  |     /// </summary> | ||||||
|  |     public bool IsNew => PageId == "new"; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// The title of the page | ||||||
|  |     /// </summary> | ||||||
|  |     [Display(ResourceType = typeof(Resources), Name = "Title")] | ||||||
|  |     [Required(AllowEmptyStrings = false)] | ||||||
|  |     public string Title { get; set; } = ""; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// The permalink for the page | ||||||
|  |     /// </summary> | ||||||
|  |     [Display(ResourceType = typeof(Resources), Name = "Permalink")] | ||||||
|  |     [Required(AllowEmptyStrings = false)] | ||||||
|  |     public string Permalink { get; set; } = ""; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Whether this page is shown in the page list | ||||||
|  |     /// </summary> | ||||||
|  |     [Display(ResourceType = typeof(Resources), Name = "ShowInPageList")] | ||||||
|  |     public bool IsShownInPageList { get; set; } = false; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// The source format for the text | ||||||
|  |     /// </summary> | ||||||
|  |     public RevisionSource Source { get; set; } = RevisionSource.Html; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// The text of the page | ||||||
|  |     /// </summary> | ||||||
|  |     [Display(ResourceType = typeof(Resources), Name = "PageText")] | ||||||
|  |     [Required(AllowEmptyStrings = false)] | ||||||
|  |     public string Text { get; set; } = ""; | ||||||
|  | 
 | ||||||
|  |     [Obsolete("Only used for model binding; use the WebLogDetails constructor")] | ||||||
|  |     public EditPageModel() : base(new()) { } | ||||||
|  | 
 | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public EditPageModel(WebLogDetails webLog) : base(webLog) { } | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Create a model from an existing page | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="page">The page from which the model will be created</param> | ||||||
|  |     /// <param name="webLog">The web log to which the page belongs</param> | ||||||
|  |     /// <returns>A populated model</returns> | ||||||
|  |     public static EditPageModel CreateFromPage(Page page, WebLogDetails webLog) | ||||||
|  |     { | ||||||
|  |         var lastRev = page.Revisions.OrderByDescending(r => r.AsOf).First(); | ||||||
|  |         return new(webLog) | ||||||
|  |         { | ||||||
|  |             PageId = page.Id, | ||||||
|  |             Title = page.Title, | ||||||
|  |             Permalink = page.Permalink, | ||||||
|  |             IsShownInPageList = page.ShowInPageList, | ||||||
|  |             Source = lastRev.SourceType, | ||||||
|  |             Text = lastRev.Text | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Populate a page from the values contained in this page | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="page">The page to be populated</param> | ||||||
|  |     /// <returns>The populated page</returns> | ||||||
|  |     public Page? PopulatePage(Page? page) | ||||||
|  |     { | ||||||
|  |         if (page == null) return null; | ||||||
|  | 
 | ||||||
|  |         page.Title = Title; | ||||||
|  |         page.Permalink = Permalink; | ||||||
|  |         page.ShowInPageList = IsShownInPageList; | ||||||
|  |         page.Revisions.Add(new() | ||||||
|  |         { | ||||||
|  |             Id = WebLogDbContext.NewId(), | ||||||
|  |             AsOf = DateTime.UtcNow, | ||||||
|  |             SourceType = Source, | ||||||
|  |             Text = Text | ||||||
|  |         }); | ||||||
|  |         return page; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,4 +1,5 @@ | |||||||
| using Microsoft.AspNetCore.Authorization; | using Markdig; | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| 
 | 
 | ||||||
| namespace MyWebLog.Features.Pages; | namespace MyWebLog.Features.Pages; | ||||||
| @ -10,20 +11,54 @@ namespace MyWebLog.Features.Pages; | |||||||
| [Authorize] | [Authorize] | ||||||
| public class PageController : MyWebLogController | public class PageController : MyWebLogController | ||||||
| { | { | ||||||
|  |     /// <summary> | ||||||
|  |     /// Pipeline with most extensions enabled | ||||||
|  |     /// </summary> | ||||||
|  |     private readonly MarkdownPipeline _pipeline = new MarkdownPipelineBuilder() | ||||||
|  |         .UseSmartyPants().UseAdvancedExtensions().Build(); | ||||||
|  | 
 | ||||||
|     /// <inheritdoc /> |     /// <inheritdoc /> | ||||||
|     public PageController(WebLogDbContext db) : base(db) { } |     public PageController(WebLogDbContext db) : base(db) { } | ||||||
| 
 | 
 | ||||||
|     [HttpGet("all")] |     [HttpGet("all")] | ||||||
|     public async Task<IActionResult> All() |     [HttpGet("all/page/{pageNbr:int}")] | ||||||
|     { |     public async Task<IActionResult> All(int? pageNbr) => | ||||||
|         await Task.CompletedTask; |         View(new PageListModel(await Db.Pages.FindPageOfPages(pageNbr ?? 1), WebLog)); | ||||||
|         throw new NotImplementedException(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     [HttpGet("{id}/edit")] |     [HttpGet("{id}/edit")] | ||||||
|     public async Task<IActionResult> Edit(string id) |     public async Task<IActionResult> Edit(string id) | ||||||
|     { |     { | ||||||
|         await Task.CompletedTask; |         if (id == "new") return View(new EditPageModel(WebLog)); | ||||||
|         throw new NotImplementedException(); | 
 | ||||||
|  |         var page = await Db.Pages.FindByIdWithRevisions(id); | ||||||
|  |         if (page == null) return NotFound(); | ||||||
|  | 
 | ||||||
|  |         return View(EditPageModel.CreateFromPage(page, WebLog)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     [HttpPost("{id}/edit")] | ||||||
|  |     public async Task<IActionResult> Save(EditPageModel model) | ||||||
|  |     { | ||||||
|  |         var page = model.PopulatePage(model.IsNew | ||||||
|  |             ? new() | ||||||
|  |             { | ||||||
|  |                 Id = WebLogDbContext.NewId(), | ||||||
|  |                 AuthorId = UserId, | ||||||
|  |                 PublishedOn = DateTime.UtcNow, | ||||||
|  |                 Revisions = new List<PageRevision>() | ||||||
|  |             } | ||||||
|  |             : await Db.Pages.GetById(model.PageId)); | ||||||
|  |         if (page == null) return NotFound(); | ||||||
|  | 
 | ||||||
|  |         page.Text = model.Source == RevisionSource.Html ? model.Text : Markdown.ToHtml(model.Text, _pipeline); | ||||||
|  |         page.UpdatedOn = DateTime.UtcNow; | ||||||
|  | 
 | ||||||
|  |         if (model.IsNew) await Db.Pages.AddAsync(page); | ||||||
|  | 
 | ||||||
|  |         await Db.SaveChangesAsync(); | ||||||
|  | 
 | ||||||
|  |         // TODO: confirmation | ||||||
|  | 
 | ||||||
|  |         return RedirectToAction(nameof(All)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								src/MyWebLog/Features/Pages/PageListModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/MyWebLog/Features/Pages/PageListModel.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | namespace MyWebLog.Features.Pages; | ||||||
|  | 
 | ||||||
|  | /// <summary> | ||||||
|  | /// View model for viewing a list of pages | ||||||
|  | /// </summary> | ||||||
|  | public class PageListModel : MyWebLogModel | ||||||
|  | { | ||||||
|  |     public IList<Page> Pages { get; init; } | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Constructor | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="pages">The pages to display</param> | ||||||
|  |     /// <param name="webLog">The web log details</param> | ||||||
|  |     public PageListModel(IList<Page> pages, WebLogDetails webLog) : base(webLog) | ||||||
|  |     { | ||||||
|  |         Pages = pages; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,7 +1,11 @@ | |||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using System.Security.Claims; | ||||||
| 
 | 
 | ||||||
| namespace MyWebLog.Features.Shared; | namespace MyWebLog.Features.Shared; | ||||||
| 
 | 
 | ||||||
|  | /// <summary> | ||||||
|  | /// Base class for myWebLog controllers | ||||||
|  | /// </summary> | ||||||
| public abstract class MyWebLogController : Controller | public abstract class MyWebLogController : Controller | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
| @ -14,6 +18,11 @@ public abstract class MyWebLogController : Controller | |||||||
|     /// </summary> |     /// </summary> | ||||||
|     protected WebLogDetails WebLog => WebLogCache.Get(HttpContext); |     protected WebLogDetails WebLog => WebLogCache.Get(HttpContext); | ||||||
| 
 | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// The ID of the currently authenticated user | ||||||
|  |     /// </summary> | ||||||
|  |     protected string UserId => User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? ""; | ||||||
|  | 
 | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Constructor |     /// Constructor | ||||||
|     /// </summary> |     /// </summary> | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								src/MyWebLog/Features/Shared/TagHelpers/YesNoTagHelper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/MyWebLog/Features/Shared/TagHelpers/YesNoTagHelper.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | using Microsoft.AspNetCore.Razor.TagHelpers; | ||||||
|  | 
 | ||||||
|  | namespace MyWebLog.Features.Shared.TagHelpers; | ||||||
|  | 
 | ||||||
|  | /// <summary> | ||||||
|  | /// Write a Yes or No based on a boolean value | ||||||
|  | /// </summary> | ||||||
|  | public class YesNoTagHelper : TagHelper | ||||||
|  | { | ||||||
|  |     /// <summary> | ||||||
|  |     /// The attribute in question | ||||||
|  |     /// </summary> | ||||||
|  |     [HtmlAttributeName("asp-for")] | ||||||
|  |     public bool For { get; set; } = false; | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Optional; if set, that value will be wrapped with <strong> instead of <span> | ||||||
|  |     /// </summary> | ||||||
|  |     [HtmlAttributeName("asp-strong-if")] | ||||||
|  |     public bool? StrongIf { get; set; } | ||||||
|  | 
 | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public override void Process(TagHelperContext context, TagHelperOutput output) | ||||||
|  |     { | ||||||
|  |         output.TagName = For == StrongIf ? "strong" : "span"; | ||||||
|  |         output.TagMode = TagMode.StartTagAndEndTag; | ||||||
|  |         output.Content.Append(For ? Resources.Yes : Resources.No); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -4,3 +4,4 @@ | |||||||
| @using MyWebLog.Properties | @using MyWebLog.Properties | ||||||
| 
 | 
 | ||||||
| @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers | ||||||
|  | @addTagHelper *, MyWebLog | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ | |||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Markdig" Version="0.27.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2"> |     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2"> | ||||||
|       <PrivateAssets>all</PrivateAssets> |       <PrivateAssets>all</PrivateAssets> | ||||||
|       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||||||
|  | |||||||
							
								
								
									
										171
									
								
								src/MyWebLog/Properties/Resources.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										171
									
								
								src/MyWebLog/Properties/Resources.Designer.cs
									
									
									
										generated
									
									
									
								
							| @ -60,6 +60,33 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Actions. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string Actions { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("Actions", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Add a New Category. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string AddANewCategory { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("AddANewCategory", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Add a New Page. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string AddANewPage { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("AddANewPage", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Admin. |         ///   Looks up a localized string similar to Admin. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -87,6 +114,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Create a New Page. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string CreateANewPage { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("CreateANewPage", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Dashboard. |         ///   Looks up a localized string similar to Dashboard. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -96,6 +132,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to MMMM d, yyyy. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string DateFormatString { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("DateFormatString", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Default Page. |         ///   Looks up a localized string similar to Default Page. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -114,6 +159,24 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Edit. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string Edit { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("Edit", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Edit Page. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string EditPage { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("EditPage", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to E-mail Address. |         ///   Looks up a localized string similar to E-mail Address. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -132,6 +195,24 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to In List?. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string InListQuestion { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("InListQuestion", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Last Updated. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string LastUpdated { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("LastUpdated", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Log Off. |         ///   Looks up a localized string similar to Log Off. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -159,6 +240,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Modify Settings. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string ModifySettings { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("ModifySettings", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Name. |         ///   Looks up a localized string similar to Name. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -168,6 +258,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to No. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string No { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("No", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Pages. |         ///   Looks up a localized string similar to Pages. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -177,6 +276,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Page Text. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string PageText { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("PageText", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Password. |         ///   Looks up a localized string similar to Password. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -186,6 +294,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Permalink. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string Permalink { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("Permalink", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Posts. |         ///   Looks up a localized string similar to Posts. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -222,6 +339,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Show in Page List. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string ShowInPageList { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("ShowInPageList", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Shown in Page List. |         ///   Looks up a localized string similar to Shown in Page List. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -276,6 +402,15 @@ namespace MyWebLog.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Title. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string Title { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("Title", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized string similar to Top Level. |         ///   Looks up a localized string similar to Top Level. | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -284,5 +419,41 @@ namespace MyWebLog.Properties { | |||||||
|                 return ResourceManager.GetString("TopLevel", resourceCulture); |                 return ResourceManager.GetString("TopLevel", resourceCulture); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to View All. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string ViewAll { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("ViewAll", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Web Log Settings. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string WebLogSettings { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("WebLogSettings", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Write a New Post. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string WriteANewPost { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("WriteANewPost", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Yes. | ||||||
|  |         /// </summary> | ||||||
|  |         public static string Yes { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("Yes", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -117,6 +117,15 @@ | |||||||
|   <resheader name="writer"> |   <resheader name="writer"> | ||||||
|     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||||
|   </resheader> |   </resheader> | ||||||
|  |   <data name="Actions" xml:space="preserve"> | ||||||
|  |     <value>Actions</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="AddANewCategory" xml:space="preserve"> | ||||||
|  |     <value>Add a New Category</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="AddANewPage" xml:space="preserve"> | ||||||
|  |     <value>Add a New Page</value> | ||||||
|  |   </data> | ||||||
|   <data name="Admin" xml:space="preserve"> |   <data name="Admin" xml:space="preserve"> | ||||||
|     <value>Admin</value> |     <value>Admin</value> | ||||||
|   </data> |   </data> | ||||||
| @ -126,21 +135,39 @@ | |||||||
|   <data name="Categories" xml:space="preserve"> |   <data name="Categories" xml:space="preserve"> | ||||||
|     <value>Categories</value> |     <value>Categories</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="CreateANewPage" xml:space="preserve"> | ||||||
|  |     <value>Create a New Page</value> | ||||||
|  |   </data> | ||||||
|   <data name="Dashboard" xml:space="preserve"> |   <data name="Dashboard" xml:space="preserve"> | ||||||
|     <value>Dashboard</value> |     <value>Dashboard</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="DateFormatString" xml:space="preserve"> | ||||||
|  |     <value>MMMM d, yyyy</value> | ||||||
|  |   </data> | ||||||
|   <data name="DefaultPage" xml:space="preserve"> |   <data name="DefaultPage" xml:space="preserve"> | ||||||
|     <value>Default Page</value> |     <value>Default Page</value> | ||||||
|   </data> |   </data> | ||||||
|   <data name="Drafts" xml:space="preserve"> |   <data name="Drafts" xml:space="preserve"> | ||||||
|     <value>Drafts</value> |     <value>Drafts</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="Edit" xml:space="preserve"> | ||||||
|  |     <value>Edit</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="EditPage" xml:space="preserve"> | ||||||
|  |     <value>Edit Page</value> | ||||||
|  |   </data> | ||||||
|   <data name="EmailAddress" xml:space="preserve"> |   <data name="EmailAddress" xml:space="preserve"> | ||||||
|     <value>E-mail Address</value> |     <value>E-mail Address</value> | ||||||
|   </data> |   </data> | ||||||
|   <data name="FirstPageOfPosts" xml:space="preserve"> |   <data name="FirstPageOfPosts" xml:space="preserve"> | ||||||
|     <value>First Page of Posts</value> |     <value>First Page of Posts</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="InListQuestion" xml:space="preserve"> | ||||||
|  |     <value>In List?</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="LastUpdated" xml:space="preserve"> | ||||||
|  |     <value>Last Updated</value> | ||||||
|  |   </data> | ||||||
|   <data name="LogOff" xml:space="preserve"> |   <data name="LogOff" xml:space="preserve"> | ||||||
|     <value>Log Off</value> |     <value>Log Off</value> | ||||||
|   </data> |   </data> | ||||||
| @ -150,15 +177,27 @@ | |||||||
|   <data name="LogOnTo" xml:space="preserve"> |   <data name="LogOnTo" xml:space="preserve"> | ||||||
|     <value>Log On to</value> |     <value>Log On to</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="ModifySettings" xml:space="preserve"> | ||||||
|  |     <value>Modify Settings</value> | ||||||
|  |   </data> | ||||||
|   <data name="Name" xml:space="preserve"> |   <data name="Name" xml:space="preserve"> | ||||||
|     <value>Name</value> |     <value>Name</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="No" xml:space="preserve"> | ||||||
|  |     <value>No</value> | ||||||
|  |   </data> | ||||||
|   <data name="Pages" xml:space="preserve"> |   <data name="Pages" xml:space="preserve"> | ||||||
|     <value>Pages</value> |     <value>Pages</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="PageText" xml:space="preserve"> | ||||||
|  |     <value>Page Text</value> | ||||||
|  |   </data> | ||||||
|   <data name="Password" xml:space="preserve"> |   <data name="Password" xml:space="preserve"> | ||||||
|     <value>Password</value> |     <value>Password</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="Permalink" xml:space="preserve"> | ||||||
|  |     <value>Permalink</value> | ||||||
|  |   </data> | ||||||
|   <data name="Posts" xml:space="preserve"> |   <data name="Posts" xml:space="preserve"> | ||||||
|     <value>Posts</value> |     <value>Posts</value> | ||||||
|   </data> |   </data> | ||||||
| @ -171,6 +210,9 @@ | |||||||
|   <data name="SaveChanges" xml:space="preserve"> |   <data name="SaveChanges" xml:space="preserve"> | ||||||
|     <value>Save Changes</value> |     <value>Save Changes</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="ShowInPageList" xml:space="preserve"> | ||||||
|  |     <value>Show in Page List</value> | ||||||
|  |   </data> | ||||||
|   <data name="ShownInPageList" xml:space="preserve"> |   <data name="ShownInPageList" xml:space="preserve"> | ||||||
|     <value>Shown in Page List</value> |     <value>Shown in Page List</value> | ||||||
|   </data> |   </data> | ||||||
| @ -189,7 +231,22 @@ | |||||||
|   <data name="TimeZone" xml:space="preserve"> |   <data name="TimeZone" xml:space="preserve"> | ||||||
|     <value>Time Zone</value> |     <value>Time Zone</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="Title" xml:space="preserve"> | ||||||
|  |     <value>Title</value> | ||||||
|  |   </data> | ||||||
|   <data name="TopLevel" xml:space="preserve"> |   <data name="TopLevel" xml:space="preserve"> | ||||||
|     <value>Top Level</value> |     <value>Top Level</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="ViewAll" xml:space="preserve"> | ||||||
|  |     <value>View All</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="WebLogSettings" xml:space="preserve"> | ||||||
|  |     <value>Web Log Settings</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="WriteANewPost" xml:space="preserve"> | ||||||
|  |     <value>Write a New Post</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="Yes" xml:space="preserve"> | ||||||
|  |     <value>Yes</value> | ||||||
|  |   </data> | ||||||
| </root> | </root> | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user