public Task <Post> GetAsync(Guid id) { var spec = new PostSpec(id); var post = _postRepo.SelectFirstOrDefaultAsync(spec, p => new Post { Id = p.Id, Title = p.Title, Slug = p.Slug, RawPostContent = p.PostContent, ContentAbstract = p.ContentAbstract, CommentEnabled = p.CommentEnabled, CreateOnUtc = p.CreateOnUtc, PubDateUtc = p.PubDateUtc, IsPublished = p.IsPublished, ExposedToSiteMap = p.ExposedToSiteMap, IsFeedIncluded = p.IsFeedIncluded, ContentLanguageCode = p.ContentLanguageCode, Tags = p.PostTag.Select(pt => new Tag { Id = pt.TagId, NormalizedName = pt.Tag.NormalizedName, DisplayName = pt.Tag.DisplayName }).ToArray(), Categories = p.PostCategory.Select(pc => new Category { Id = pc.CategoryId, DisplayName = pc.Category.DisplayName, RouteName = pc.Category.RouteName, Note = pc.Category.Note }).ToArray() }); return(post); }
private async Task <IReadOnlyList <FeedEntry> > GetFeedEntriesAsync(Guid?categoryId = null) { int?top = null; if (_blogConfig.FeedSettings.RssItemCount != 0) { top = _blogConfig.FeedSettings.RssItemCount; } var postSpec = new PostSpec(categoryId, top); var list = await _postRepo.SelectAsync(postSpec, p => p.PubDateUtc != null?new FeedEntry { Id = p.Id.ToString(), Title = p.Title, PubDateUtc = p.PubDateUtc.Value, Description = _blogConfig.FeedSettings.UseFullContent ? p.PostContent : p.ContentAbstract, Link = $"{_baseUrl}/post/{p.PubDateUtc.Value.Year}/{p.PubDateUtc.Value.Month}/{p.PubDateUtc.Value.Day}/{p.Slug}", Author = _blogConfig.FeedSettings.AuthorName, AuthorEmail = _blogConfig.NotificationSettings.AdminEmail, Categories = p.PostCategory.Select(pc => pc.Category.DisplayName).ToArray() } : null); // Workaround EF limitation // Man, this is super ugly if (_blogConfig.FeedSettings.UseFullContent && list.Any()) { foreach (var simpleFeedItem in list) { simpleFeedItem.Description = FormatPostContent(simpleFeedItem.Description); } } return(list); }
public Task <Post> Handle(GetPostByIdQuery request, CancellationToken cancellationToken) { var spec = new PostSpec(request.Id); var post = _postRepo.SelectFirstOrDefaultAsync(spec, Post.EntitySelector); return(post); }
private Task <IReadOnlyList <SimpleFeedItem> > GetPostsAsFeedItemsAsync(Guid?categoryId = null) { Logger.LogInformation($"{nameof(GetPostsAsFeedItemsAsync)} - {nameof(categoryId)}: {categoryId}"); int?top = null; if (_blogConfig.FeedSettings.RssItemCount != 0) { top = _blogConfig.FeedSettings.RssItemCount; } var postSpec = new PostSpec(categoryId, top); return(_postRepository.SelectAsync(postSpec, p => p.PostPublish.PubDateUtc != null ? new SimpleFeedItem { Id = p.Id.ToString(), Title = p.Title, PubDateUtc = p.PostPublish.PubDateUtc.Value, Description = p.ContentAbstract, Link = $"{_baseUrl}/post/{p.PostPublish.PubDateUtc.Value.Year}/{p.PostPublish.PubDateUtc.Value.Month}/{p.PostPublish.PubDateUtc.Value.Day}/{p.Slug}", Author = _blogConfig.FeedSettings.AuthorName, AuthorEmail = _blogConfig.EmailSettings.AdminEmail, Categories = p.PostCategory.Select(pc => pc.Category.DisplayName).ToList() } : null)); }
public Task <Response <PostSlugMetaModel> > GetMetaAsync(int year, int month, int day, string slug) { return(TryExecuteAsync <PostSlugMetaModel>(async() => { var date = new DateTime(year, month, day); var spec = new PostSpec(date, slug); var model = await _postRepository.SelectFirstOrDefaultAsync(spec, post => new PostSlugMetaModel { Title = post.Title, PubDateUtc = post.PostPublish.PubDateUtc.GetValueOrDefault(), LastModifyOnUtc = post.PostPublish.LastModifiedUtc, Categories = post.PostCategory .Select(pc => pc.Category.DisplayName) .ToArray(), Tags = post.PostTag .Select(pt => pt.Tag.DisplayName) .ToArray() }); return new SuccessResponse <PostSlugMetaModel>(model); })); }
public async Task <IReadOnlyList <PostListItem> > GetArchivedPostsAsync(int year, int month = 0) { if (year < DateTime.MinValue.Year || year > DateTime.MaxValue.Year) { Logger.LogError($"parameter '{nameof(year)}:{year}' is out of range"); throw new ArgumentOutOfRangeException(nameof(year)); } if (month > 12 || month < 0) { Logger.LogError($"parameter '{nameof(month)}:{month}' is out of range"); throw new ArgumentOutOfRangeException(nameof(month)); } var spec = new PostSpec(year, month); var list = await _postRepository.SelectAsync(spec, p => new PostListItem { Title = p.Title, Slug = p.Slug, ContentAbstract = p.ContentAbstract, PubDateUtc = p.PostPublish.PubDateUtc.GetValueOrDefault() }); return(list); }
public Task <IReadOnlyList <PostListEntry> > ListPostsAsync(int year, int month = 0) { if (year < DateTime.MinValue.Year || year > DateTime.MaxValue.Year) { _logger.LogError($"parameter '{nameof(year)}:{year}' is out of range"); throw new ArgumentOutOfRangeException(nameof(year)); } if (month is > 12 or < 0) { _logger.LogError($"parameter '{nameof(month)}:{month}' is out of range"); throw new ArgumentOutOfRangeException(nameof(month)); } var spec = new PostSpec(year, month); var list = _postRepo.SelectAsync(spec, p => new PostListEntry { Title = p.Title, Slug = p.Slug, ContentAbstract = p.ContentAbstract, PubDateUtc = p.PubDateUtc.GetValueOrDefault(), LangCode = p.ContentLanguageCode, Tags = p.PostTag.Select(pt => new Tag { NormalizedName = pt.Tag.NormalizedName, DisplayName = pt.Tag.DisplayName }) }); return(list); }
private IReadOnlyList <SimpleFeedItem> GetPostsAsFeedItems(Guid?categoryId = null) { Logger.LogInformation($"{nameof(GetPostsAsFeedItems)} - {nameof(categoryId)}: {categoryId}"); int?top = null; if (_blogConfig.FeedSettings.RssItemCount != 0) { top = _blogConfig.FeedSettings.RssItemCount; } var postSpec = new PostSpec(categoryId, top); var items = _postRepository.Select(postSpec, p => p.PostPublish.PubDateUtc != null ? new SimpleFeedItem { Id = p.Id.ToString(), Title = p.Title, PubDateUtc = p.PostPublish.PubDateUtc.Value, Description = p.ContentAbstract, Link = GetPostLink(p.PostPublish.PubDateUtc.Value, p.Slug), Author = _blogConfig.FeedSettings.AuthorName, AuthorEmail = _blogConfig.EmailConfiguration.AdminEmail, Categories = p.PostCategory.Select(pc => pc.Category.DisplayName).ToList() } : null); return(items); }
public Task <IReadOnlyList <PostListItem> > GetPagedPostsAsync(int pageSize, int pageIndex, Guid?categoryId = null) { if (pageSize < 1) { throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than 1, current value: {pageSize}."); } if (pageIndex < 1) { throw new ArgumentOutOfRangeException(nameof(pageIndex), $"{nameof(pageIndex)} can not be less than 1, current value: {pageIndex}."); } var spec = new PostSpec(pageSize, pageIndex, categoryId); return(_postRepository.SelectAsync(spec, p => new PostListItem { Title = p.Title, Slug = p.Slug, ContentAbstract = p.ContentAbstract, PubDateUtc = p.PostPublish.PubDateUtc.GetValueOrDefault(), Tags = p.PostTag.Select(pt => new Tag { NormalizedTagName = pt.Tag.NormalizedName, TagName = pt.Tag.DisplayName }).ToList() })); }
public async Task <PostSlug> GetDraftPreviewAsync(Guid postId) { var spec = new PostSpec(postId); var postSlugModel = await _postRepo.SelectFirstOrDefaultAsync(spec, post => new PostSlug { Title = post.Title, ContentAbstract = post.ContentAbstract, PubDateUtc = DateTime.UtcNow, Categories = post.PostCategory.Select(pc => pc.Category).Select(p => new Category { DisplayName = p.DisplayName, RouteName = p.RouteName }).ToArray(), RawPostContent = post.PostContent, Tags = post.PostTag.Select(pt => pt.Tag) .Select(p => new Tag { NormalizedName = p.NormalizedName, DisplayName = p.DisplayName }).ToArray(), Id = post.Id, ExposedToSiteMap = post.ExposedToSiteMap, LastModifyOnUtc = post.LastModifiedUtc, ContentLanguageCode = post.ContentLanguageCode }); return(postSlugModel); }
public Task <string> GetRawContentAsync(PostSlugInfo slugInfo) { var date = new DateTime(slugInfo.Year, slugInfo.Month, slugInfo.Day); var spec = new PostSpec(date, slugInfo.Slug); return(_postRepo.SelectFirstOrDefaultAsync(spec, post => post.PostContent)); }
public Task <Response <PostSlugModel> > GetAsync(int year, int month, int day, string slug) { return(TryExecuteAsync <PostSlugModel>(async() => { var date = new DateTime(year, month, day); var spec = new PostSpec(date, slug); var pid = await _postRepository.SelectFirstOrDefaultAsync(spec, p => p.Id); if (pid != Guid.Empty) { var psm = await _cache.GetOrCreateAsync($"post-{pid}", async entry => { entry.SlidingExpiration = TimeSpan.FromMinutes(AppSettings.CacheSlidingExpirationMinutes["Post"]); var postSlugModel = await _postRepository.SelectFirstOrDefaultAsync(spec, post => new PostSlugModel { Title = post.Title, Abstract = post.ContentAbstract, PubDateUtc = post.PostPublish.PubDateUtc.GetValueOrDefault(), Categories = post.PostCategory.Select(pc => pc.Category).Select(p => new Category { DisplayName = p.DisplayName, RouteName = p.RouteName }).ToList(), Content = post.PostContent, Hits = post.PostExtension.Hits, Likes = post.PostExtension.Likes, Tags = post.PostTag.Select(pt => pt.Tag) .Select(p => new Tag { NormalizedName = p.NormalizedName, DisplayName = p.DisplayName }).ToList(), PostId = post.Id, CommentEnabled = post.CommentEnabled, IsExposedToSiteMap = post.PostPublish.ExposedToSiteMap, LastModifyOnUtc = post.PostPublish.LastModifiedUtc, LangCode = post.PostPublish.ContentLanguageCode, CommentCount = post.Comment.Count(c => c.IsApproved) }); if (null != postSlugModel) { postSlugModel.Content = Utils.AddLazyLoadToImgTag(postSlugModel.Content); } return postSlugModel; }); return new SuccessResponse <PostSlugModel>(psm); } return new SuccessResponse <PostSlugModel>(null); })); }
public async Task <PostSlug> GetAsync(PostSlugInfo slugInfo) { var date = new DateTime(slugInfo.Year, slugInfo.Month, slugInfo.Day); var spec = new PostSpec(date, slugInfo.Slug); var pid = await _postRepository.SelectFirstOrDefaultAsync(spec, p => p.Id); if (pid == Guid.Empty) { return(null); } var psm = await _cache.GetOrCreateAsync(CacheDivision.Post, $"{pid}", async entry => { entry.SlidingExpiration = TimeSpan.FromMinutes(AppSettings.CacheSlidingExpirationMinutes["Post"]); var postSlugModel = await _postRepository.SelectFirstOrDefaultAsync(spec, post => new PostSlug { Title = post.Title, ContentAbstract = post.ContentAbstract, PubDateUtc = post.PubDateUtc.GetValueOrDefault(), Categories = post.PostCategory.Select(pc => pc.Category).Select(p => new Category { DisplayName = p.DisplayName, RouteName = p.RouteName }).ToArray(), RawPostContent = post.PostContent, Hits = post.PostExtension.Hits, Likes = post.PostExtension.Likes, Tags = post.PostTag.Select(pt => pt.Tag) .Select(p => new Tag { NormalizedName = p.NormalizedName, DisplayName = p.DisplayName }).ToArray(), Id = post.Id, CommentEnabled = post.CommentEnabled, ExposedToSiteMap = post.ExposedToSiteMap, LastModifyOnUtc = post.LastModifiedUtc, ContentLanguageCode = post.ContentLanguageCode, CommentCount = post.Comment.Count(c => c.IsApproved) }); if (null != postSlugModel) { postSlugModel.RawPostContent = AddLazyLoadToImgTag(postSlugModel.RawPostContent); } return(postSlugModel); }); return(psm); }
public async Task <CommentDetailedItem> CreateAsync(CommentRequest request) { if (_blogConfig.ContentSettings.EnableWordFilter) { switch (_blogConfig.ContentSettings.WordFilterMode) { case WordFilterMode.Mask: request.Username = await _commentModerator.ModerateContent(request.Username); request.Content = await _commentModerator.ModerateContent(request.Content); break; case WordFilterMode.Block: if (await _commentModerator.HasBadWord(request.Username, request.Content)) { await Task.CompletedTask; return(null); } break; } } var model = new CommentEntity { Id = Guid.NewGuid(), Username = request.Username, CommentContent = request.Content, PostId = request.PostId, CreateTimeUtc = DateTime.UtcNow, Email = request.Email, IPAddress = request.IpAddress, IsApproved = !_blogConfig.ContentSettings.RequireCommentReview }; await _commentRepo.AddAsync(model); var spec = new PostSpec(request.PostId, false); var postTitle = _postRepo.SelectFirstOrDefault(spec, p => p.Title); var item = new CommentDetailedItem { Id = model.Id, CommentContent = model.CommentContent, CreateTimeUtc = model.CreateTimeUtc, Email = model.Email, IpAddress = model.IPAddress, IsApproved = model.IsApproved, PostTitle = postTitle, Username = model.Username }; return(item); }
public Task <Response> DeleteRecycledPostsAsync() { return(TryExecuteAsync(async() => { var spec = new PostSpec(true); var posts = await _postRepository.GetAsync(spec); await _postRepository.DeleteAsync(posts); return new SuccessResponse(); })); }
public Task <Response> DeleteRecycledPostsAsync() { return(TryExecuteAsync(async() => { var spec = new PostSpec(true); var posts = await _postRepository.GetAsync(spec); await _postRepository.DeleteAsync(posts); await _moongladeAudit.AddAuditEntry(EventType.Content, AuditEventId.EmptyRecycleBin, "Emptied Recycle Bin."); return new SuccessResponse(); })); }
public Task <Response <string> > GetRawContentAsync(int year, int month, int day, string slug) { return(TryExecuteAsync <string>(async() => { var date = new DateTime(year, month, day); var spec = new PostSpec(date, slug); var model = await _postRepository.SelectFirstOrDefaultAsync(spec, post => post.PostContent); return new SuccessResponse <string>(model); })); }
public Task <Response <CommentListItem> > CreateAsync(NewCommentRequest request) { return(TryExecuteAsync <CommentListItem>(async() => { // 1. Check comment enabled or not if (!_blogConfig.ContentSettings.EnableComments) { return new FailedResponse <CommentListItem>((int)ResponseFailureCode.CommentDisabled); } // 2. Harmonize banned keywords if (_blogConfig.ContentSettings.EnableWordFilter) { var dw = _blogConfig.ContentSettings.DisharmonyWords; var maskWordFilter = new MaskWordFilter(new StringWordSource(dw)); request.Username = maskWordFilter.FilterContent(request.Username); request.Content = maskWordFilter.FilterContent(request.Content); } var model = new CommentEntity { Id = Guid.NewGuid(), Username = request.Username, CommentContent = request.Content, PostId = request.PostId, CreateOnUtc = DateTime.UtcNow, Email = request.Email, IPAddress = request.IpAddress, IsApproved = !_blogConfig.ContentSettings.RequireCommentReview, UserAgent = request.UserAgent }; await _commentRepository.AddAsync(model); var spec = new PostSpec(request.PostId, false); var postTitle = _postRepository.SelectFirstOrDefault(spec, p => p.Title); var item = new CommentListItem { Id = model.Id, CommentContent = model.CommentContent, CreateOnUtc = model.CreateOnUtc, Email = model.Email, IpAddress = model.IPAddress, IsApproved = model.IsApproved, PostTitle = postTitle, Username = model.Username }; return new SuccessResponse <CommentListItem>(item); })); }
public async Task DeleteRecycledAsync() { var spec = new PostSpec(true); var posts = await _postRepository.GetAsync(spec); await _postRepository.DeleteAsync(posts); await _blogAudit.AddAuditEntry(EventType.Content, AuditEventId.EmptyRecycleBin, "Emptied Recycle Bin."); foreach (var guid in posts.Select(p => p.Id)) { _cache.Remove(CacheDivision.Post, guid.ToString()); } }
public async Task <Unit> Handle(PurgeRecycledCommand request, CancellationToken cancellationToken) { var spec = new PostSpec(true); var posts = await _postRepo.GetAsync(spec); await _postRepo.DeleteAsync(posts); foreach (var guid in posts.Select(p => p.Id)) { _cache.Remove(CacheDivision.Post, guid.ToString()); } return(Unit.Value); }
public Task <IReadOnlyList <PostMetaData> > GetPostMetaListAsync(PostPublishStatus postPublishStatus) { var spec = new PostSpec(postPublishStatus); return(_postRepository.SelectAsync(spec, p => new PostMetaData { Id = p.Id, Title = p.Title, PubDateUtc = p.PostPublish.PubDateUtc, IsPublished = p.PostPublish.IsPublished, IsDeleted = p.PostPublish.IsDeleted, Revision = p.PostPublish.Revision, CreateOnUtc = p.CreateOnUtc, Hits = p.PostExtension.Hits })); }
public Task <IReadOnlyList <PostSegment> > ListSegmentAsync(PostPublishStatus postPublishStatus) { var spec = new PostSpec(postPublishStatus); return(_postRepo.SelectAsync(spec, p => new PostSegment { Id = p.Id, Title = p.Title, Slug = p.Slug, PubDateUtc = p.PubDateUtc, IsPublished = p.IsPublished, IsDeleted = p.IsDeleted, CreateOnUtc = p.CreateOnUtc, Hits = p.PostExtension.Hits })); }
public Task <Response> DeleteRecycledAsync() { return(TryExecuteAsync(async() => { var spec = new PostSpec(true); var posts = await _postRepository.GetAsync(spec); await _postRepository.DeleteAsync(posts); await _moongladeAudit.AddAuditEntry(EventType.Content, AuditEventId.EmptyRecycleBin, "Emptied Recycle Bin."); foreach (var guid in posts.Select(p => p.Id)) { _cache.Remove($"post-{guid}"); } return new SuccessResponse(); })); }
public Task <IReadOnlyList <PostDigest> > Handle(ListArchiveQuery request, CancellationToken cancellationToken) { if (request.Year < DateTime.MinValue.Year || request.Year > DateTime.MaxValue.Year) { throw new ArgumentOutOfRangeException(nameof(request.Year)); } if (request.Month is > 12 or < 0) { throw new ArgumentOutOfRangeException(nameof(request.Month)); } var spec = new PostSpec(request.Year, request.Month.GetValueOrDefault()); var list = _postRepo.SelectAsync(spec, PostDigest.EntitySelector); return(list); }
public async Task <IReadOnlyList <Archive> > ListAsync() { if (!_postRepo.Any(p => p.IsPublished && !p.IsDeleted)) { return(new List <Archive>()); } var spec = new PostSpec(PostPublishStatus.Published); var list = await _postRepo.SelectAsync(spec, post => new { post.PubDateUtc.Value.Year, post.PubDateUtc.Value.Month }, monthList => new Archive( monthList.Key.Year, monthList.Key.Month, monthList.Count())); return(list); }
public Task <Response <PostSlugModel> > GetPostAsync(int year, int month, int day, string slug) { return(TryExecuteAsync <PostSlugModel>(async() => { var date = new DateTime(year, month, day); var spec = new PostSpec(date, slug); var postSlugModel = await _postRepository.SelectFirstOrDefaultAsync(spec, post => new PostSlugModel { Title = post.Title, Abstract = post.ContentAbstract, PubDateUtc = post.PostPublish.PubDateUtc.GetValueOrDefault(), Categories = post.PostCategory.Select(pc => pc.Category).Select(p => new Category { DisplayName = p.DisplayName, RouteName = p.RouteName }).ToList(), Content = post.PostContent, Hits = post.PostExtension.Hits, Likes = post.PostExtension.Likes, Tags = post.PostTag.Select(pt => pt.Tag) .Select(p => new Tag { NormalizedTagName = p.NormalizedName, TagName = p.DisplayName }).ToList(), PostId = post.Id, CommentEnabled = post.CommentEnabled, IsExposedToSiteMap = post.PostPublish.ExposedToSiteMap, LastModifyOnUtc = post.PostPublish.LastModifiedUtc, CommentCount = post.Comment.Count(c => c.IsApproved) }); if (null != postSlugModel) { postSlugModel.Content = Utils.AddLazyLoadToImgTag(postSlugModel.Content); } return new SuccessResponse <PostSlugModel>(postSlugModel); })); }
public async Task<CommentDetailedItem> CreateAsync(NewCommentRequest request) { if (_blogConfig.ContentSettings.EnableWordFilter) { var dw = _blogConfig.ContentSettings.DisharmonyWords; var maskWordFilter = new MaskWordFilter(new StringWordSource(dw)); request.Username = maskWordFilter.FilterContent(request.Username); request.Content = maskWordFilter.FilterContent(request.Content); } var model = new CommentEntity { Id = Guid.NewGuid(), Username = request.Username, CommentContent = request.Content, PostId = request.PostId, CreateOnUtc = DateTime.UtcNow, Email = request.Email, IPAddress = request.IpAddress, IsApproved = !_blogConfig.ContentSettings.RequireCommentReview }; await _commentRepository.AddAsync(model); var spec = new PostSpec(request.PostId, false); var postTitle = _postRepository.SelectFirstOrDefault(spec, p => p.Title); var item = new CommentDetailedItem { Id = model.Id, CommentContent = model.CommentContent, CreateOnUtc = model.CreateOnUtc, Email = model.Email, IpAddress = model.IPAddress, IsApproved = model.IsApproved, PostTitle = postTitle, Username = model.Username }; return item; }
public async Task <Post> Handle(GetPostBySlugQuery request, CancellationToken cancellationToken) { var date = new DateTime(request.Slug.Year, request.Slug.Month, request.Slug.Day); // Try to find by checksum var slugCheckSum = Helper.ComputeCheckSum($"{request.Slug.Slug}#{date:yyyyMMdd}"); ISpecification <PostEntity> spec = new PostSpec(slugCheckSum); var pid = await _postRepo.SelectFirstOrDefaultAsync(spec, p => p.Id); if (pid == Guid.Empty) { // Post does not have a checksum, fall back to old method spec = new PostSpec(date, request.Slug.Slug); pid = await _postRepo.SelectFirstOrDefaultAsync(spec, x => x.Id); if (pid == Guid.Empty) { return(null); } // Post is found, fill it's checksum so that next time the query can be run against checksum var p = await _postRepo.GetAsync(pid); p.HashCheckSum = slugCheckSum; await _postRepo.UpdateAsync(p); } var psm = await _cache.GetOrCreateAsync(CacheDivision.Post, $"{pid}", async entry => { entry.SlidingExpiration = TimeSpan.FromMinutes(_settings.CacheSlidingExpirationMinutes["Post"]); var post = await _postRepo.SelectFirstOrDefaultAsync(spec, Post.EntitySelector); return(post); }); return(psm); }
public Task <PostSlugSegment> GetSegmentAsync(PostSlugInfo slugInfo) { var date = new DateTime(slugInfo.Year, slugInfo.Month, slugInfo.Day); var spec = new PostSpec(date, slugInfo.Slug); var model = _postRepo.SelectFirstOrDefaultAsync(spec, post => new PostSlugSegment { Title = post.Title, PubDateUtc = post.PubDateUtc.GetValueOrDefault(), LastModifyOnUtc = post.LastModifiedUtc, Categories = post.PostCategory .Select(pc => pc.Category.DisplayName) .ToArray(), Tags = post.PostTag .Select(pt => pt.Tag.DisplayName) .ToArray() }); return(model); }
public Task <Response <PostSlugModel> > GetDraftPreviewAsync(Guid postId) { return(TryExecuteAsync <PostSlugModel>(async() => { var spec = new PostSpec(postId); var postSlugModel = await _postRepository.SelectFirstOrDefaultAsync(spec, post => new PostSlugModel { Title = post.Title, Abstract = post.ContentAbstract, PubDateUtc = DateTime.UtcNow, Categories = post.PostCategory.Select(pc => pc.Category).Select(p => new Category { DisplayName = p.DisplayName, RouteName = p.RouteName }).ToList(), Content = post.PostContent, Tags = post.PostTag.Select(pt => pt.Tag) .Select(p => new Tag { NormalizedName = p.NormalizedName, DisplayName = p.DisplayName }).ToList(), PostId = post.Id, IsExposedToSiteMap = post.PostPublish.ExposedToSiteMap, LastModifyOnUtc = post.PostPublish.LastModifiedUtc, LangCode = post.PostPublish.ContentLanguageCode }); if (null != postSlugModel) { postSlugModel.Content = Utils.AddLazyLoadToImgTag(postSlugModel.Content); } return new SuccessResponse <PostSlugModel>(postSlugModel); })); }