Edit and create blog posts

This commit is contained in:
Robert Marshall 2020-01-03 10:47:13 +00:00
parent 47431d4650
commit 44875a6a45
6 changed files with 126 additions and 1 deletions

View 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");
}
}
}

View file

@ -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});
}
}
}

View file

@ -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());
}
}
}
}

View file

@ -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;
}
}

View 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; }
}
}

View 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>