Edit and create blog posts
This commit is contained in:
parent
47431d4650
commit
44875a6a45
6 changed files with 126 additions and 1 deletions
31
Website.Tests/Models/BlogPostTests.cs
Normal file
31
Website.Tests/Models/BlogPostTests.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using FluentAssertions;
|
||||
using Website.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace Website.Tests.Models {
|
||||
public class BlogPostTests {
|
||||
[Fact]
|
||||
public void UpdateTitle_WithNewTitle_UpdatesTitlePropertyAndRegeneratesUrl() {
|
||||
var post = new BlogPost();
|
||||
post.UpdateTitle("new title");
|
||||
|
||||
post.Title.Should().Be("new title");
|
||||
post.Url.Should().Be("new-title");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateDraft_WithContent_UpdatesDraftProperty() {
|
||||
var post = new BlogPost();
|
||||
post.UpdateDraft("content");
|
||||
post.Draft.Should().Be("content");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Publish_SetsContentToDraft() {
|
||||
var post = new BlogPost();
|
||||
post.UpdateDraft("content");
|
||||
post.Publish();
|
||||
post.Content.Should().Be("content");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,13 +3,14 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Website.Data;
|
||||
using Website.Models;
|
||||
using Website.ViewModels;
|
||||
|
||||
namespace Website.Controllers
|
||||
{
|
||||
public class BlogController : Controller
|
||||
{
|
||||
const int MaxPostsPerPage = 10;
|
||||
private const int MaxPostsPerPage = 10;
|
||||
private readonly BlogRepository _repo;
|
||||
|
||||
public BlogController(BlogRepository repo)
|
||||
|
@ -36,5 +37,35 @@ namespace Website.Controllers
|
|||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Edit(int? id) {
|
||||
if (!id.HasValue)
|
||||
return View();
|
||||
|
||||
try {
|
||||
var post = await _repo.GetPostByIdAsync(id.Value);
|
||||
var model = new BlogPostSubmission {
|
||||
Id = post.Id,
|
||||
Title = post.Title,
|
||||
Content = post.Draft
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
catch (InvalidOperationException) {
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Save(BlogPostSubmission submission) {
|
||||
var post = submission.Id.HasValue ? await _repo.GetPostByIdAsync(submission.Id.Value) : new BlogPost();
|
||||
|
||||
post.UpdateTitle(submission.Title);
|
||||
post.UpdateDraft(submission.Content);
|
||||
|
||||
var savedPost = await _repo.SavePost(post);
|
||||
|
||||
return RedirectToAction(nameof(Edit), new{savedPost.Id});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,5 +42,27 @@ namespace Website.Data
|
|||
return result.First();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BlogPost> GetPostByIdAsync(int id) {
|
||||
const string query = "SELECT * FROM blog_posts WHERE post_id=@id AND post_deleted=0";
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<BlogPostState>(query, new {id});
|
||||
return new BlogPost(result.First());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BlogPost> SavePost(BlogPost post) {
|
||||
const string newPostQuery = "INSERT INTO blog_posts (post_title, post_content, post_draft, post_url) VALUES (@title, @content, @draft, @url); SELECT CAST(LAST_INSERT_ID() as int)";
|
||||
const string updatePostQuery = "UPDATE blog_posts SET post_id = @id, post_title = @title, post_content = @content, post_draft = @draft, post_url = @url WHERE post_id = @id ";
|
||||
|
||||
var query = post.Id == 0 ? newPostQuery : updatePostQuery;
|
||||
|
||||
using (var connection = _dbProvider.NewConnection()) {
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<int>(query, post);
|
||||
return await GetPostByIdAsync(result.Single());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,10 @@ namespace Website.Models
|
|||
{
|
||||
public class BlogPost
|
||||
{
|
||||
public BlogPost() {
|
||||
|
||||
}
|
||||
|
||||
public BlogPost(BlogPostState state)
|
||||
{
|
||||
Id = state.Post_Id;
|
||||
|
@ -23,5 +27,17 @@ namespace Website.Models
|
|||
public string Draft { get; private set; }
|
||||
public string Url { get; private set; }
|
||||
public int UserId { get; private set; }
|
||||
|
||||
private void GenerateUrl() {
|
||||
Url = Title.Replace(' ', '-');
|
||||
}
|
||||
|
||||
public void UpdateTitle(string title) {
|
||||
Title = title;
|
||||
GenerateUrl();
|
||||
}
|
||||
|
||||
public void UpdateDraft(string content) => Draft = content;
|
||||
public void Publish() => Content = Draft;
|
||||
}
|
||||
}
|
7
Website/Models/BlogPostSubmission.cs
Normal file
7
Website/Models/BlogPostSubmission.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Website.Models {
|
||||
public class BlogPostSubmission {
|
||||
public int? Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Content { get; set; }
|
||||
}
|
||||
}
|
18
Website/Views/Blog/Edit.cshtml
Normal file
18
Website/Views/Blog/Edit.cshtml
Normal file
|
@ -0,0 +1,18 @@
|
|||
@model Website.Models.BlogPostSubmission
|
||||
|
||||
@{
|
||||
ViewBag.Title = Model != null ? "Edit Post" : "New Post";
|
||||
}
|
||||
|
||||
<form method="post" action="/blog/save">
|
||||
<input type="hidden" name="id" value="@Model?.Id"/>
|
||||
<label for="postTitle">Title: </label><input name="title" id="postTitle" value="@Model?.Title"/>
|
||||
<textarea id="postContent" name="content">@Model?.Content</textarea>
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
|
||||
<script>
|
||||
var simpleMde = new SimpleMDE({ element: document.getElementById("postContent"), tabSize: 4 });
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue