Post Edit & create

pull/318/head v0.3.1
Yunus Emre Kalkan 7 years ago
parent f520c7e541
commit f62ed01ac2

@ -12,5 +12,7 @@ namespace Volo.Blogging.Blogs
Task<ListResultDto<BlogDto>> GetListAsync();
Task<BlogDto> GetByShortNameAsync(string shortName);
Task<BlogDto> GetAsync(Guid id);
}
}

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Volo.Blogging.Posts
{
public class CreatePostDto
{
public Guid BlogId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
}

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Volo.Blogging.Posts
{
public class GetPostForEditOutput : FullAuditedEntityDto<Guid>
{
public Guid BlogId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
}

@ -9,8 +9,14 @@ namespace Volo.Blogging.Posts
{
public interface IPostAppService : IApplicationService
{
ListResultDto<PostDto> GetPostsByBlogId(Guid id);
ListResultDto<PostWithDetailsDto> GetListByBlogIdAsync(Guid id);
Task<PostDto> GetPost(GetPostInput input);
Task<PostWithDetailsDto> GetByTitleAsync(GetPostInput input);
Task<PostWithDetailsDto> GetAsync(Guid id);
Task<PostWithDetailsDto> CreateAsync(CreatePostDto input);
Task<PostWithDetailsDto> UpdateAsync(Guid id, UpdatePostDto input);
}
}

@ -3,14 +3,12 @@ using Volo.Abp.Application.Dtos;
namespace Volo.Blogging.Posts
{
public class PostDto : EntityDto<Guid>
public class PostDto : FullAuditedEntityDto<Guid>
{
public Guid BlogId { get; protected set; }
public string Title { get; protected set; }
public string Content { get; set; }
public DateTime CreationTime { get; set; }
}
}

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Volo.Blogging.Posts
{
public class PostWithDetailsDto : FullAuditedEntityDto<Guid>
{
public Guid BlogId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
}

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Volo.Blogging.Posts
{
public class UpdatePostDto
{
public Guid BlogId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
}

@ -1,4 +1,5 @@
using AutoMapper;
using Volo.Abp.AutoMapper;
using Volo.Blogging.Blogs;
using Volo.Blogging.Posts;
@ -10,6 +11,7 @@ namespace Volo.Blogging
{
CreateMap<Blog, BlogDto>();
CreateMap<Post, PostDto>();
CreateMap<Post, PostWithDetailsDto>();
}
}
}

@ -14,6 +14,11 @@ namespace Volo.Blogging
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<BloggingApplicationAutoMapperProfile>(validate: true);
});
services.AddAssemblyOf<BloggingApplicationModule>();
}
}

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
@ -34,6 +35,12 @@ namespace Volo.Blogging.Blogs
return ObjectMapper.Map<Blog, BlogDto>(blog);
}
public async Task<BlogDto> GetAsync(Guid id)
{
var blog = await _blogRepository.GetAsync(id);
return ObjectMapper.Map<Blog, BlogDto>(blog);
}
}
}

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using System.Collections.Generic;
using Volo.Abp.Users;
namespace Volo.Blogging.Posts
{
@ -16,19 +17,52 @@ namespace Volo.Blogging.Posts
_postRepository = postRepository;
}
public ListResultDto<PostDto> GetPostsByBlogId(Guid id)
public ListResultDto<PostWithDetailsDto> GetListByBlogIdAsync(Guid id)
{
var posts = _postRepository.GetPostsByBlogId(id);
return new ListResultDto<PostDto>(
ObjectMapper.Map<List<Post>, List<PostDto>>(posts));
return new ListResultDto<PostWithDetailsDto>(
ObjectMapper.Map<List<Post>, List<PostWithDetailsDto>>(posts));
}
public async Task<PostDto> GetPost(GetPostInput input)
public async Task<PostWithDetailsDto> GetByTitleAsync(GetPostInput input)
{
var post = await _postRepository.GetPost(input.BlogId, input.Title);
return ObjectMapper.Map<Post,PostDto>(post);
return ObjectMapper.Map<Post, PostWithDetailsDto>(post);
}
public async Task<PostWithDetailsDto> GetAsync(Guid id)
{
var post = await _postRepository.GetAsync(id);
return ObjectMapper.Map<Post, PostWithDetailsDto>(post);
}
public async Task<PostWithDetailsDto> UpdateAsync(Guid id, UpdatePostDto input)
{
var post = await _postRepository.GetAsync(id);
post.SetTitle(input.Title);
post.Content = input.Content;
post = await _postRepository.UpdateAsync(post);
return ObjectMapper.Map<Post, PostWithDetailsDto>(post);
}
public async Task<PostWithDetailsDto> CreateAsync(CreatePostDto input)
{
var post = new Post(
GuidGenerator.Create(),
blogId: input.BlogId,
creatorId: CurrentUser.GetId(),
title: input.Title
) {Content = input.Content};
await _postRepository.InsertAsync(post);
return ObjectMapper.Map<Post, PostWithDetailsDto>(post);
}
}
}

@ -35,6 +35,8 @@ namespace Volo.Blogging
//TODO: Make configurable!
options.Conventions.AddPageRoute("/Blog/Posts/Index", "blog/{blogShortName}");
options.Conventions.AddPageRoute("/Blog/Posts/Detail", "blog/{blogShortName}/{postTitle}");
options.Conventions.AddPageRoute("/Blog/Posts/Edit", "blog/{blogShortName}/manage/{postId}");
options.Conventions.AddPageRoute("/Blog/Posts/New", "blog/{blogShortName}/manage/new");
});
services.AddAssemblyOf<BloggingWebModule>();

@ -8,4 +8,8 @@
<p>@Model.Post.Content</p>
<i>Posted to @Model.Blog.Name On @Model.Post.CreationTime</i>
<p>
<i>Posted to @Model.Blog.Name On @Model.Post.CreationTime</i>
</p>
<a asp-page="./Edit" asp-route-postId="@Model.Post.Id" asp-route-blogShortName="@Model.BlogShortName">edit</a>

@ -20,7 +20,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
[BindProperty(SupportsGet = true)]
public string PostTitle { get; set; }
public PostDto Post { get; set; }
public PostWithDetailsDto Post { get; set; }
public BlogDto Blog { get; set; }
@ -34,7 +34,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
var blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Post = await _postAppService.GetPost(new GetPostInput {BlogId = blog.Id , Title = PostTitle});
Post = await _postAppService.GetByTitleAsync(new GetPostInput {BlogId = blog.Id , Title = PostTitle});
Blog = blog;
}
}

@ -0,0 +1,31 @@
@page
@using Volo.Blogging.Pages.Blog.Posts
@model EditModel
@{
}
@using (Html.BeginForm(FormMethod.Post))
{
<div class="form-group">
<label class="col-sm-2 control-label">Title</label>
<div class="col-sm-10">
<input class="form-control" name="Title" value="@Model.Post.Title">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Content</label>
<div class="col-sm-10">
<textarea rows="4" class="form-control" name="Content">@Model.Post.Content</textarea>
</div>
</div>
<input name="BlogId" value="@Model.Post.BlogId" hidden="">
<input name="Id" value="@Model.Post.Id" hidden="">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Save</button>
</div>
</div>
}

@ -0,0 +1,49 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.Application.Dtos;
using Volo.Blogging.Blogs;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Blog.Posts
{
public class EditModel : PageModel
{
private readonly IPostAppService _postAppService;
private readonly IBlogAppService _blogAppService;
[BindProperty(SupportsGet = true)]
public string BlogShortName { get; set; }
[BindProperty(SupportsGet = true)]
public string PostId { get; set; }
public PostWithDetailsDto Post { get; set; }
public BlogDto Blog { get; set; }
public EditModel(IPostAppService postAppService, IBlogAppService blogAppService)
{
_postAppService = postAppService;
_blogAppService = blogAppService;
}
public async void OnGet()
{
var blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Post = await _postAppService.GetAsync(new Guid(PostId));
Blog = blog;
}
public async Task<ActionResult> OnPost(Guid id, UpdatePostDto post)
{
var editedPost = await _postAppService.UpdateAsync(id, post);
var blog = await _blogAppService.GetAsync(editedPost.BlogId);
return Redirect(Url.Content($"~/blog/{blog.ShortName}/{editedPost.Title}"));
}
}
}

@ -10,6 +10,8 @@
<ul>
@foreach (var post in Model.Posts)
{
<li><a asp-page="./Detail" asp-route-postTitle="@post.Title" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a></li>
<li><a asp-page="./Detail" asp-route-postTitle="@post.Title" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a></li>
}
</ul>
<a asp-page="./New" asp-route-blogShortName="@Model.BlogShortName">Create New Post</a>

@ -19,7 +19,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
[BindProperty(SupportsGet = true)]
public string BlogShortName { get; set; }
public IReadOnlyList<PostDto> Posts { get; set; }
public IReadOnlyList<PostWithDetailsDto> Posts { get; set; }
public IndexModel(IPostAppService postAppService, IBlogAppService blogAppService)
{
@ -31,7 +31,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
var blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Posts = _postAppService.GetPostsByBlogId(blog.Id).Items;
Posts = _postAppService.GetListByBlogIdAsync(blog.Id).Items;
}
}
}

@ -0,0 +1,30 @@
@page
@using Volo.Blogging.Pages.Blog.Posts
@model NewModel
@{
}
@using (Html.BeginForm(FormMethod.Post))
{
<div class="form-group">
<label class="col-sm-2 control-label">Title</label>
<div class="col-sm-10">
<input class="form-control" name="Title" value="@Model.Post.Title">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Content</label>
<div class="col-sm-10">
<textarea rows="4" class="form-control" name="Content">@Model.Post.Content</textarea>
</div>
</div>
<input name="BlogId" value="@Model.Post.BlogId" hidden="">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Save</button>
</div>
</div>
}

@ -0,0 +1,52 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.Application.Dtos;
using Volo.Blogging.Blogs;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Blog.Posts
{
public class NewModel : PageModel
{
private readonly IPostAppService _postAppService;
private readonly IBlogAppService _blogAppService;
[BindProperty(SupportsGet = true)]
public string BlogShortName { get; set; }
[BindProperty(SupportsGet = true)]
public string PostId { get; set; }
public PostWithDetailsDto Post { get; set; }
public BlogDto Blog { get; set; }
public NewModel(IPostAppService postAppService, IBlogAppService blogAppService)
{
_postAppService = postAppService;
_blogAppService = blogAppService;
}
public async void OnGet()
{
var blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Post = new PostWithDetailsDto()
{
BlogId = blog.Id
};
Blog = blog;
}
public async Task<ActionResult> OnPost(CreatePostDto post)
{
var insertedPost = await _postAppService.CreateAsync(post);
var blog = await _blogAppService.GetAsync(insertedPost.BlogId);
return Redirect(Url.Content($"~/blog/{blog.ShortName}/{insertedPost.Title}"));
}
}
}

@ -24,4 +24,14 @@
<Content Remove="Pages\Blog\Posts\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Pages\Blog\Posts\Edit.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Update="Pages\Blog\Posts\Edit.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack>
</Content>
</ItemGroup>
</Project>

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Volo.Blogging.Blogs;
using Volo.Blogging.Posts;
using Xunit;
namespace Volo.Blogging
{
public class PostAppService_Tests : BloggingApplicationTestBase
{
private readonly IPostAppService _postAppService;
private readonly IBlogRepository _blogRepository;
private readonly BloggingTestData _testData;
public PostAppService_Tests()
{
_testData = GetRequiredService<BloggingTestData>();
_postAppService = GetRequiredService<IPostAppService>();
_blogRepository = GetRequiredService<IBlogRepository>();
}
[Fact]
public async Task Should_Create_A_Post()
{
var blogId = (await _blogRepository.GetListAsync()).First().Id;
var title = "title";
var content = "content";
var newPost = await _postAppService.CreateAsync(new CreatePostDto()
{
BlogId = blogId,
Title = title,
Content = content
});
UsingDbContext(context =>
{
var post = context.Posts.FirstOrDefault(q => q.Title == title);
post.ShouldNotBeNull();
post.Title.ShouldBe(title);
post.Content.ShouldBe(content);
post.BlogId.ShouldBe(blogId);
});
}
[Fact]
public async Task Should_Create_And_Update_A_Post()
{
var blogId = (await _blogRepository.GetListAsync()).First().Id;
var title = "title";
var newTitle = "newtitle";
var content = "content";
var newPost = await _postAppService.CreateAsync(new CreatePostDto()
{
BlogId = blogId,
Title = title,
Content = content
});
await _postAppService.UpdateAsync(newPost.Id, new UpdatePostDto()
{
BlogId = blogId,
Title = newTitle,
Content = content
});
UsingDbContext(context =>
{
var post = context.Posts.FirstOrDefault(q => q.Id == newPost.Id);
post.ShouldNotBeNull();
post.Title.ShouldBe(newTitle);
post.Content.ShouldBe(content);
post.BlogId.ShouldBe(blogId);
});
}
}
}
Loading…
Cancel
Save