|
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic; |
|
|
|
using Microsoft.AspNetCore.Authorization; |
|
|
|
using Microsoft.Extensions.Caching.Distributed; |
|
|
|
using Volo.Abp.Caching; |
|
|
|
using Volo.Abp.EventBus.Local; |
|
|
|
using Volo.Blogging.Comments; |
|
|
|
using Volo.Blogging.Tagging; |
|
|
|
using Volo.Blogging.Tagging.Dtos; |
|
|
|
@ -20,41 +21,92 @@ namespace Volo.Blogging.Posts |
|
|
|
private readonly IPostRepository _postRepository; |
|
|
|
private readonly ITagRepository _tagRepository; |
|
|
|
private readonly ICommentRepository _commentRepository; |
|
|
|
private readonly IDistributedCache<ListResultDto<PostWithDetailsDto>> _postsCache; |
|
|
|
|
|
|
|
public PostAppService(IPostRepository postRepository, ITagRepository tagRepository, ICommentRepository commentRepository, IBlogUserLookupService userLookupService, IDistributedCache<ListResultDto<PostWithDetailsDto>> postsCache) |
|
|
|
private readonly IDistributedCache<List<PostCacheItem>> _postsCache; |
|
|
|
private readonly ILocalEventBus _localEventBus; |
|
|
|
|
|
|
|
public PostAppService( |
|
|
|
IPostRepository postRepository, |
|
|
|
ITagRepository tagRepository, |
|
|
|
ICommentRepository commentRepository, |
|
|
|
IBlogUserLookupService userLookupService, |
|
|
|
IDistributedCache<List<PostCacheItem>> postsCache, |
|
|
|
ILocalEventBus localEventBus |
|
|
|
) |
|
|
|
{ |
|
|
|
UserLookupService = userLookupService; |
|
|
|
_postRepository = postRepository; |
|
|
|
_tagRepository = tagRepository; |
|
|
|
_commentRepository = commentRepository; |
|
|
|
_postsCache = postsCache; |
|
|
|
_localEventBus = localEventBus; |
|
|
|
} |
|
|
|
|
|
|
|
public async Task<ListResultDto<PostWithDetailsDto>> GetListByBlogIdAndTagName(Guid id, string tagName) |
|
|
|
{ |
|
|
|
var cacheKey = id.ToString() + "-" + tagName; |
|
|
|
var posts = await _postRepository.GetPostsByBlogId(id); |
|
|
|
var tag = tagName.IsNullOrWhiteSpace() ? null : await _tagRepository.FindByNameAsync(id, tagName); |
|
|
|
var userDictionary = new Dictionary<Guid, BlogUserDto>(); |
|
|
|
var postDtos = new List<PostWithDetailsDto>(ObjectMapper.Map<List<Post>, List<PostWithDetailsDto>>(posts)); |
|
|
|
|
|
|
|
return await _postsCache.GetOrAddAsync( |
|
|
|
cacheKey, |
|
|
|
async () => await GetPostsByBlogIdAndTagName(id, tagName), |
|
|
|
() => new DistributedCacheEntryOptions |
|
|
|
foreach (var postDto in postDtos) |
|
|
|
{ |
|
|
|
postDto.Tags = await GetTagsOfPost(postDto.Id); |
|
|
|
} |
|
|
|
|
|
|
|
if (tag != null) |
|
|
|
{ |
|
|
|
postDtos = await FilterPostsByTag(postDtos, tag); |
|
|
|
} |
|
|
|
|
|
|
|
foreach (var postDto in postDtos) |
|
|
|
{ |
|
|
|
if (postDto.CreatorId.HasValue) |
|
|
|
{ |
|
|
|
AbsoluteExpiration = DateTimeOffset.Now.AddHours(6) |
|
|
|
if (!userDictionary.ContainsKey(postDto.CreatorId.Value)) |
|
|
|
{ |
|
|
|
var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); |
|
|
|
if (creatorUser != null) |
|
|
|
{ |
|
|
|
userDictionary[creatorUser.Id] = ObjectMapper.Map<BlogUser, BlogUserDto>(creatorUser); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (userDictionary.ContainsKey(postDto.CreatorId.Value)) |
|
|
|
{ |
|
|
|
postDto.Writer = userDictionary[(Guid)postDto.CreatorId]; |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
return new ListResultDto<PostWithDetailsDto>(postDtos); |
|
|
|
} |
|
|
|
|
|
|
|
public async Task<ListResultDto<PostWithDetailsDto>> GetTimeOrderedListAsync(Guid blogId) |
|
|
|
{ |
|
|
|
return await _postsCache.GetOrAddAsync( |
|
|
|
var postCacheItems = await _postsCache.GetOrAddAsync( |
|
|
|
blogId.ToString(), |
|
|
|
async () => await GetTimeOrderedPostsAsync(blogId), |
|
|
|
() => new DistributedCacheEntryOptions |
|
|
|
{ |
|
|
|
AbsoluteExpiration = DateTimeOffset.Now.AddHours(6) |
|
|
|
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1) |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
var postsWithDetails = ObjectMapper.Map<List<PostCacheItem>, List<PostWithDetailsDto>>(postCacheItems); |
|
|
|
|
|
|
|
foreach (var post in postsWithDetails) |
|
|
|
{ |
|
|
|
if (post.CreatorId.HasValue) |
|
|
|
{ |
|
|
|
var creatorUser = await UserLookupService.FindByIdAsync(post.CreatorId.Value); |
|
|
|
if (creatorUser != null) |
|
|
|
{ |
|
|
|
post.Writer = ObjectMapper.Map<BlogUser, BlogUserDto>(creatorUser); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return new ListResultDto<PostWithDetailsDto>(postsWithDetails); |
|
|
|
} |
|
|
|
|
|
|
|
public async Task<PostWithDetailsDto> GetForReadingAsync(GetPostInput input) |
|
|
|
@ -107,6 +159,7 @@ namespace Volo.Blogging.Posts |
|
|
|
await _commentRepository.DeleteOfPost(id); |
|
|
|
|
|
|
|
await _postRepository.DeleteAsync(id); |
|
|
|
await PublishPostChangedEventAsync(post.BlogId); |
|
|
|
} |
|
|
|
|
|
|
|
[Authorize(BloggingPermissions.Posts.Update)] |
|
|
|
@ -128,6 +181,7 @@ namespace Volo.Blogging.Posts |
|
|
|
|
|
|
|
var tagList = SplitTags(input.Tags); |
|
|
|
await SaveTags(tagList, post); |
|
|
|
await PublishPostChangedEventAsync(post.BlogId); |
|
|
|
|
|
|
|
return ObjectMapper.Map<Post, PostWithDetailsDto>(post); |
|
|
|
} |
|
|
|
@ -153,66 +207,16 @@ namespace Volo.Blogging.Posts |
|
|
|
|
|
|
|
var tagList = SplitTags(input.Tags); |
|
|
|
await SaveTags(tagList, post); |
|
|
|
await PublishPostChangedEventAsync(post.BlogId); |
|
|
|
|
|
|
|
return ObjectMapper.Map<Post, PostWithDetailsDto>(post); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task<ListResultDto<PostWithDetailsDto>> GetPostsByBlogIdAndTagName(Guid id, string tagName) |
|
|
|
{ |
|
|
|
var posts = await _postRepository.GetPostsByBlogId(id); |
|
|
|
var tag = tagName.IsNullOrWhiteSpace() ? null : await _tagRepository.FindByNameAsync(id, tagName); |
|
|
|
var userDictionary = new Dictionary<Guid, BlogUserDto>(); |
|
|
|
var postDtos = new List<PostWithDetailsDto>(ObjectMapper.Map<List<Post>, List<PostWithDetailsDto>>(posts)); |
|
|
|
|
|
|
|
foreach (var postDto in postDtos) |
|
|
|
{ |
|
|
|
postDto.Tags = await GetTagsOfPost(postDto.Id); |
|
|
|
} |
|
|
|
|
|
|
|
if (tag != null) |
|
|
|
{ |
|
|
|
postDtos = await FilterPostsByTag(postDtos, tag); |
|
|
|
} |
|
|
|
|
|
|
|
foreach (var postDto in postDtos) |
|
|
|
{ |
|
|
|
if (postDto.CreatorId.HasValue) |
|
|
|
{ |
|
|
|
if (!userDictionary.ContainsKey(postDto.CreatorId.Value)) |
|
|
|
{ |
|
|
|
var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); |
|
|
|
if (creatorUser != null) |
|
|
|
{ |
|
|
|
userDictionary[creatorUser.Id] = ObjectMapper.Map<BlogUser, BlogUserDto>(creatorUser); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (userDictionary.ContainsKey(postDto.CreatorId.Value)) |
|
|
|
{ |
|
|
|
postDto.Writer = userDictionary[(Guid)postDto.CreatorId]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return new ListResultDto<PostWithDetailsDto>(postDtos); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task<ListResultDto<PostWithDetailsDto>> GetTimeOrderedPostsAsync(Guid blogId) |
|
|
|
private async Task<List<PostCacheItem>> GetTimeOrderedPostsAsync(Guid blogId) |
|
|
|
{ |
|
|
|
var posts = await _postRepository.GetOrderedList(blogId); |
|
|
|
|
|
|
|
var postDtos = new List<PostWithDetailsDto>(ObjectMapper.Map<List<Post>, List<PostWithDetailsDto>>(posts)); |
|
|
|
|
|
|
|
foreach (var postDto in postDtos) |
|
|
|
{ |
|
|
|
var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); |
|
|
|
if (creatorUser != null) |
|
|
|
{ |
|
|
|
postDto.Writer = ObjectMapper.Map<BlogUser, BlogUserDto>(creatorUser); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return new ListResultDto<PostWithDetailsDto>(postDtos); |
|
|
|
return ObjectMapper.Map<List<Post>, List<PostCacheItem>>(posts); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task<string> RenameUrlIfItAlreadyExistAsync(Guid blogId, string url, Post existingPost = null) |
|
|
|
@ -300,5 +304,14 @@ namespace Volo.Blogging.Posts |
|
|
|
|
|
|
|
return Task.FromResult(filteredPostDtos); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task PublishPostChangedEventAsync(Guid blogId) |
|
|
|
{ |
|
|
|
await _localEventBus.PublishAsync( |
|
|
|
new PostChangedEvent |
|
|
|
{ |
|
|
|
BlogId = blogId |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|