Browse Source

Merge pull request #12087 from abpframework/pr/11964

Implements send to admin approval to publish
pull/12153/head
Enis Necipoglu 4 years ago
committed by GitHub
parent
commit
6cf8060b29
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs
  2. 25
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  3. 21
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogPostAdminClientProxy.Generated.cs
  4. 26
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs
  5. 5
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml
  6. 4
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml.cs
  7. 16
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml
  8. 17
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js
  9. 56
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/index.js
  10. 23
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/wwwroot/client-proxies/cms-kit-admin-proxy.js
  11. 3
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostStatus.cs
  12. 14
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  13. 9
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json
  14. 5
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs
  15. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs
  16. 6
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs
  17. 8
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs

10
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs

@ -14,8 +14,14 @@ public interface IBlogPostAdminAppService
UpdateBlogPostDto>
{
Task PublishAsync(Guid id);
Task DraftAsync(Guid id);
Task<BlogPostDto> CreateAndPublishAsync(CreateBlogPostDto input);
Task SendToReviewAsync(Guid id);
Task<BlogPostDto> CreateAndSendToReviewAsync(CreateBlogPostDto input);
Task<bool> HasBlogPostWaitingForReviewAsync();
}

25
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs

@ -151,4 +151,29 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe
blogPost.Status = BlogPostStatus.Published;
return blogPost;
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public virtual async Task SendToReviewAsync(Guid id)
{
var blogPost = await BlogPostRepository.GetAsync(id);
blogPost.SetWaitingForReview();
await BlogPostRepository.UpdateAsync(blogPost);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public virtual async Task<BlogPostDto> CreateAndSendToReviewAsync(CreateBlogPostDto input)
{
var blogPost = await CreateAsync(input);
await CurrentUnitOfWork.SaveChangesAsync();
await SendToReviewAsync(blogPost.Id);
blogPost.Status = BlogPostStatus.WaitingForReview;
return blogPost;
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Publish)]
public async Task<bool> HasBlogPostWaitingForReviewAsync()
{
return await BlogPostRepository.HasBlogPostWaitingForReviewAsync();
}
}

21
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogPostAdminClientProxy.Generated.cs

@ -79,4 +79,25 @@ public partial class BlogPostAdminClientProxy : ClientProxyBase<IBlogPostAdminAp
{ typeof(CreateBlogPostDto), input }
});
}
public virtual async Task SendToReviewAsync(Guid id)
{
await RequestAsync(nameof(SendToReviewAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id },
});
}
public virtual async Task<BlogPostDto> CreateAndSendToReviewAsync(CreateBlogPostDto input)
{
return await RequestAsync<BlogPostDto>(nameof(CreateAndSendToReviewAsync), new ClientProxyRequestTypeValue
{
{ typeof(CreateBlogPostDto), input }
});
}
public virtual async Task<bool> HasBlogPostWaitingForReviewAsync()
{
return await RequestAsync<bool>(nameof(HasBlogPostWaitingForReviewAsync));
}
}

26
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs

@ -86,4 +86,28 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS
{
return BlogPostAdminAppService.CreateAndPublishAsync(input);
}
}
[HttpPost]
[Route("{id}/send-to-review")]
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public virtual Task SendToReviewAsync(Guid id)
{
return BlogPostAdminAppService.SendToReviewAsync(id);
}
[HttpPost]
[Route("create-and-send-to-review")]
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public virtual Task<BlogPostDto> CreateAndSendToReviewAsync(CreateBlogPostDto input)
{
return BlogPostAdminAppService.CreateAndSendToReviewAsync(input);
}
[HttpGet]
[Route("has-blogpost-waiting-for-review")]
[Authorize(CmsKitAdminPermissions.BlogPosts.Publish)]
public virtual Task<bool> HasBlogPostWaitingForReviewAsync()
{
return BlogPostAdminAppService.HasBlogPostWaitingForReviewAsync();
}
}

5
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml

@ -87,10 +87,13 @@
</abp-card-body>
<abp-card-footer>
<abp-button button-type="Primary" type="button" text="@L["Draft"].Value" id="button-blog-post-create" />
<abp-button button-type="Primary" type="button" text="@L["SaveAsDraft"].Value" id="button-blog-post-create" />
@if ((await AuthorizationService.AuthorizeAsync(CmsKitAdminPermissions.BlogPosts.Publish)).Succeeded)
{
<abp-button button-type="Primary" type="button" text="@L["Publish"].Value" id="button-blog-post-publish"/>
}else
{
<abp-button button-type="Primary" type="button" text="@L["SendToReviewToPublish"].Value" id="button-blog-post-send-to-review"/>
}
</abp-card-footer>
</abp-card>

4
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml.cs

@ -36,6 +36,10 @@ public class CreateModel : CmsKitAdminPageModel
{
createResult = await BlogPostAdminAppService.CreateAndPublishAsync(dto);
}
else if (ViewModel.Status == BlogPostStatus.WaitingForReview)
{
createResult = await BlogPostAdminAppService.CreateAndSendToReviewAsync(dto);
}
else
{
createResult = await BlogPostAdminAppService.CreateAsync(dto);

16
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml

@ -5,6 +5,7 @@
@using Volo.CmsKit.Admin.Web.Pages
@using Volo.CmsKit.Admin.Web.Menus
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar
@using Volo.CmsKit.Blogs
@inherits CmsKitAdminPageBase
@ -27,11 +28,24 @@
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new {pageName = typeof(IndexModel).FullName})
}
<div class="alert alert-warning" style="display: none" role="alert" id="alertHasBlogPostWaitingForReview">
<abp-button button-type="Link" type="button" text="@L["HasBlogPostWaitingForReviewMessage"].Value" id="button-show-waiting-for-review"/>
</div>
<abp-card class="mb-4">
<abp-card-body>
<div id="CmsKitBlogPostsWrapper">
<abp-row>
<abp-column>
<abp-column size="_2">
<select id="StatusSelect" class="form-select">
<option value="">@L["SelectAStatus"]</option>
@foreach (var status in (BlogPostStatus[]) Enum.GetValues(typeof(BlogPostStatus)))
{
<option value="@((int)status)">@L["CmsKit.BlogPost.Status." + (int)status]</option>
}
</select>
</abp-column>
<abp-column size="_10">
@await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent))
</abp-column>
</abp-row>

17
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js

@ -4,7 +4,8 @@ $(function () {
var blogPostStatus = {
Draft: 0,
Published: 1
Published: 1,
SendToReview: 2
};
var $selectBlog = $('#BlogSelectionSelect');
@ -16,6 +17,7 @@ $(function () {
var $status = $('#ViewModel_Status');
var $buttonSubmit = $('#button-blog-post-create');
var $buttonPublish = $('#button-blog-post-publish');
var $buttonSendToReview = $('#button-blog-post-send-to-review');
var $pageContentInput = $('#ViewModel_Content');
var $tagsInput = $('.tag-editor-form input[name=tags]');
var $fileInput = $('#BlogPostCoverImage');
@ -83,6 +85,19 @@ $(function () {
);
});
$buttonSendToReview.click(function (e) {
abp.message.confirm(
l('BlogPostSendToReviewConfirmationMessage', $title.val()),
function (isConfirmed) {
if (isConfirmed) {
e.preventDefault();
$status.val(blogPostStatus.SendToReview);
submitCoverImage();
}
}
);
});
function submitEntityTags(blogPostId) {
if ($tagsInput.val()) {

56
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/index.js

@ -1,17 +1,26 @@
$(function () {
var l = abp.localization.getResource("CmsKit");
var $statusFilter = $("#StatusSelect");
var blogPostStatus = {
Draft: 0,
Published: 1
Published: 1,
SendToReview: 2
};
var blogsService = volo.cmsKit.admin.blogs.blogPostAdmin;
var getFilter = function () {
return {
var filter = {
filter: $('#CmsKitBlogPostsWrapper input.page-search-filter-text').val()
};
if ($statusFilter.val()) {
filter.status = $statusFilter.val();
}
return filter;
};
var dataTable = $("#BlogPostsTable").DataTable(abp.libs.datatables.normalizeConfiguration({
@ -51,6 +60,25 @@ $(function () {
.then(function () {
dataTable.ajax.reload();
abp.notify.success(l('SuccessfullyPublished'));
checkHasBlogPostWaitingForReview();
});
}
},
{
text: l('SendToReview'),
visible: function(data) {
return data?.status === blogPostStatus.Draft &&
!abp.auth.isGranted('CmsKit.BlogPosts.Publish');
},
confirmMessage: function (data) {
return l("BlogPostPublishConfirmationMessage", data.record.title)
},
action: function (data) {
blogsService
.sendToReview(data.record.id)
.then(function () {
dataTable.ajax.reload();
abp.notify.success(l('BlogPostSendToReviewSuccessMessage', data.record.title));
});
}
},
@ -68,6 +96,7 @@ $(function () {
.then(function () {
dataTable.ajax.reload();
abp.notify.success(l('SuccessfullySaved'));
checkHasBlogPostWaitingForReview();
});
}
},
@ -130,4 +159,25 @@ $(function () {
e.preventDefault();
window.location.href = "BlogPosts/Create"
});
$('#button-show-waiting-for-review').on('click', function (e) {
e.preventDefault();
$statusFilter.val(blogPostStatus.SendToReview);
dataTable.ajax.reload();
});
function checkHasBlogPostWaitingForReview(){
if (!abp.auth.isGranted('CmsKit.BlogPosts.Publish')){
$('#alertHasBlogPostWaitingForReview').hide();
}
blogsService.hasBlogPostWaitingForReview().then(function (result) {
if (result) {
$('#alertHasBlogPostWaitingForReview').show('fast');
} else {
$('#alertHasBlogPostWaitingForReview').hide('fast');
}
});
}
checkHasBlogPostWaitingForReview();
});

23
modules/cms-kit/src/Volo.CmsKit.Admin.Web/wwwroot/client-proxies/cms-kit-admin-proxy.js

@ -415,6 +415,29 @@
}, ajaxParams));
};
volo.cmsKit.admin.blogs.blogPostAdmin.sendToReview = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-admin/blogs/blog-posts/' + id + '/send-to-review',
type: 'POST',
dataType: null
}, ajaxParams));
};
volo.cmsKit.admin.blogs.blogPostAdmin.createAndSendToReview = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-admin/blogs/blog-posts/create-and-send-to-review',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.cmsKit.admin.blogs.blogPostAdmin.hasBlogPostWaitingForReview = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-admin/blogs/blog-posts/has-blogpost-waiting-for-review',
type: 'GET'
}, ajaxParams));
};
})();
})();

3
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostStatus.cs

@ -3,5 +3,6 @@
public enum BlogPostStatus
{
Draft,
Published
Published,
WaitingForReview
}

14
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json

@ -169,16 +169,20 @@
"SavedSuccessfully": "Saved successfully",
"CmsKit.BlogPost.Status.0": "Draft",
"CmsKit.BlogPost.Status.1": "Published",
"CmsKit.BlogPost.Status.2": "Waiting for review",
"BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?",
"SuccessfullyPublished": "Successfully published!",
"Draft": "Draft",
"Publish": "Publish",
"BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?",
"SelectAnAuthor": "Select an author",
"GoToTop": "Go to top",
"InThisDocument": "In this document",
"RemoveCoverImageConfirmationMessage": "Are you sure to remove the cover image?",
"RemoveCoverImage": "Remove the cover image",
"BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?",
"SaveAsDraft": "Save as draft",
"SendToReview": "Send to review",
"SendToReviewToPublish": "Send to review to publish",
"BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.",
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
"SelectAStatus": "Select a status",
"Status": "Status",
"CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts"
}
}

9
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json

@ -168,11 +168,20 @@
"SavedSuccessfully": "Başarıyla kaydedildi",
"CmsKit.BlogPost.Status.0": "Taslak",
"CmsKit.BlogPost.Status.1": "Yayınlandı",
"CmsKit.BlogPost.Status.2": "İnceleme Bekliyor",
"BlogPostPublishConfirmationMessage": "\"{0}\" başlıklı gönderiyi yayınlamak istediğinize emin misiniz?",
"SuccessfullyPublished": "Başarıyla yayınlandı",
"Draft": "Taslak olarak kaydet",
"Publish": "Yayınla",
"BlogPostDraftConfirmationMessage": "\"{0}\" başlıklı gönderiyi taslak haline getirmek istediğinize emin misiniz?",
"BlogPostSendToReviewConfirmationMessage": "\"{0}\" başlıklı gönderiyi yayınlamak için admin incelemesine göndermek istediğinize emin misiniz?",
"SaveAsDraft": "Taslak olarak kaydet",
"SendToReview": "İncelemeye gönder",
"SendToReviewToPublish": "Yayınlamak için admin incelemesine gönder",
"BlogPostSendToReviewSuccessMessage": "\"{0}\" başlıklı gönderiyi yayınlamak için admin incelemesine gönderildi.",
"HasBlogPostWaitingForReviewMessage": "Yayınlanmak için onay bekleyen blog postlar var! Listelemek için tıklayın.",
"SelectAStatus": "Durum seçin",
"Status": "Durum",
"SelectAnAuthor": "Bir yazar seçin",
"GoToTop": "Yukarı Git",
"InThisDocument": "Bu belgede",

5
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs

@ -91,4 +91,9 @@ public class BlogPost : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
Status = BlogPostStatus.Published;
}
public virtual void SetWaitingForReview()
{
Status = BlogPostStatus.WaitingForReview;
}
}

2
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs

@ -40,4 +40,6 @@ public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid>
Task<int> GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default);
Task<CmsUser> GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default);
Task<bool> HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default);
}

6
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs

@ -132,4 +132,10 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
{
return (await GetDbContextAsync()).BlogPosts.Select(x => x.Author).Distinct();
}
public virtual async Task<bool> HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.AnyAsync(x => x.Status == BlogPostStatus.WaitingForReview, GetCancellationToken(cancellationToken));
}
}

8
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs

@ -151,4 +151,12 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
.Select(s => s.user)
.Distinct();
}
public virtual async Task<bool> HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken))
.AnyAsync(x => x.Status == BlogPostStatus.WaitingForReview, cancellationToken);
}
}

Loading…
Cancel
Save