Piranha CMS - Site-wide Cross-Site Request Forgery (CSRF)
Description
In PiranhaCMS, versions 4.0.0-alpha1 to 9.2.0 are vulnerable to cross-site request forgery (CSRF) when performing various actions supported by the management system, such as deleting a user, deleting a role, editing a post, deleting a media folder etc., when an ID is known.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
PiranhaCMS 4.0.0-alpha1 to 9.2.0 is vulnerable to CSRF, enabling an attacker to perform privileged actions like user deletion if the target's ID is known.
Vulnerability
PiranhaCMS versions 4.0.0-alpha1 through 9.2.0 are vulnerable to cross-site request forgery (CSRF) in the management system interface. The flaw affects multiple administrative actions—such as deleting a user, deleting a role, editing a post, or deleting a media folder—when the attacker knows the target resource's ID. No anti-CSRF token or origin validation is enforced on the corresponding endpoints [1][4].
Exploitation
An attacker must trick an authenticated administrator into visiting a malicious page while the admin has an active session with the PiranhaCMS manager. The attacker must also know the numeric or string ID of the resource to be targeted (e.g., a user ID). The malicious page then submits a forged request (e.g., via a form or image tag) to the vulnerable endpoint, causing the action to be executed with the admin's privileges [1][4].
Impact
Successful exploitation allows an attacker to perform arbitrary management actions on behalf of an authenticated administrator, including deleting users, deleting roles, editing posts, or deleting media folders. This can lead to unauthorized data loss, disruption of content, and privilege escalation if critical accounts are removed [1][4].
Mitigation
A fix was introduced in commit e42abacdd0dd880ce9cf6607efcc24646ac82eda which adds validation to the login flow and removes unsafe modal comments; however, a fully patched release version is not explicitly named in the available references. Users should upgrade to any version later than 9.2.0 if available, or apply the relevant security patches from the official repository. If no newer release exists, administrators should implement additional CSRF protections such as anti-forgery tokens or restrict management interface access to trusted networks [2][3]. No KEV listing has been published for this CVE.
- NVD - CVE-2021-25976
- Merge pull request #1742 from PiranhaCMS/features/manager-security-up… · PiranhaCMS/piranha.core@e42abac
- GitHub - PiranhaCMS/piranha.core: Piranha CMS is the friendly editor-focused CMS for .NET that can be used both as an integrated CMS or as a headless API.
- 2021-25976 | Mend Vulnerability Database
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
PiranhaNuGet | >= 4.0.0-alpha1, < 10.0-alpha1 | 10.0-alpha1 |
Affected products
2- PiranhaCMS/Piranhav5Range: 4.0.0-alpha1
Patches
1e42abacdd0ddMerge pull request #1742 from PiranhaCMS/features/manager-security-update
73 files changed · +1051 −630
core/Piranha.Manager/Areas/Manager/Pages/Index.cshtml.cs+1 −1 modified@@ -24,7 +24,7 @@ public IndexModel(IAuthorizationService service) { _service = service; } - public async Task<IActionResult> OnGet() + public async Task<IActionResult> OnGet(string returnUrl = null) { var items = await Menu.Items.GetForUser(HttpContext.User, _service);
core/Piranha.Manager/Areas/Manager/Shared/_Layout.cshtml+6 −1 modified@@ -1,4 +1,5 @@ -@{ +@inject Microsoft.Extensions.Options.IOptions<ManagerOptions> Options +@{ var module = Piranha.App.Modules.Get<Piranha.Manager.Module>(); var prerelease = Piranha.Utils.IsPreRelease(typeof(Piranha.Manager.Module).Assembly) ? "pre-release" : ""; var isRightToLeft = @System.Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft; @@ -53,6 +54,10 @@ var piranha = {}; window.piranha = piranha; piranha.baseUrl = "@Url.Content("~/")"; + piranha.antiForgery = { + cookieName: "@Options.Value.XsrfCookieName", + headerName: "@Options.Value.XsrfHeaderName" + }; </script> <partial name="~/Areas/Manager/Shared/Partial/_EditorConfig.cshtml" />
core/Piranha.Manager/Areas/Manager/Shared/Partial/_ContentPickerModal.cshtml+0 −1 modified@@ -1,6 +1,5 @@ @inject ManagerLocalizer Localizer -<!-- The Modal --> <div class="modal modal-panel fade" id="contentpicker"> <div class="modal-dialog modal-lg"> <div class="modal-content">
core/Piranha.Manager/Areas/Manager/Shared/Partial/_MediaPickerModal.cshtml+0 −1 modified@@ -1,7 +1,6 @@ @inject IAuthorizationService Auth @inject ManagerLocalizer Localizer -<!-- The Modal --> <div class="modal modal-panel fade" id="mediapicker"> <div class="modal-dialog modal-lg"> <div class="modal-content">
core/Piranha.Manager/Areas/Manager/Shared/Partial/_PagePickerModal.cshtml+0 −1 modified@@ -1,6 +1,5 @@ @inject ManagerLocalizer Localizer -<!-- The Modal --> <div class="modal modal-panel fade" id="pagepicker"> <div class="modal-dialog modal-lg"> <div class="modal-content">
core/Piranha.Manager/Areas/Manager/Shared/Partial/_PostPickerModal.cshtml+0 −1 modified@@ -1,6 +1,5 @@ @inject ManagerLocalizer Localizer -<!-- The Modal --> <div class="modal modal-panel fade" id="postpicker"> <div class="modal-dialog modal-lg"> <div class="modal-content">
core/Piranha.Manager/Areas/Manager/Shared/Partial/_PreviewModal.cshtml+0 −1 modified@@ -1,7 +1,6 @@ @inject IAuthorizationService Auth @inject ManagerLocalizer Localizer -<!-- The Modal --> <div class="modal fade" id="previewModal"> <div class="modal-dialog modal-lg"> <div class="modal-content">
core/Piranha.Manager/assets/dist/css/full.min.css+5 −5 modifiedcore/Piranha.Manager/assets/dist/css/slim.min.css+5 −5 modifiedcore/Piranha.Manager/assets/dist/js/piranha.alias.js+43 −36 modified@@ -44,43 +44,45 @@ } fetch(piranha.baseUrl + "manager/api/alias/save", { - method: "post", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - id: piranha.alias.model.id, - siteId: piranha.alias.siteId, - aliasUrl: piranha.alias.model.aliasUrl, - redirectUrl: piranha.alias.model.redirectUrl, - isPermanent: piranha.alias.model.isPermanent != null ? piranha.alias.model.isPermanent : false - }) + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify({ + id: piranha.alias.model.id, + siteId: piranha.alias.siteId, + aliasUrl: piranha.alias.model.aliasUrl, + redirectUrl: piranha.alias.model.redirectUrl, + isPermanent: piranha.alias.model.isPermanent != null ? piranha.alias.model.isPermanent : false }) - .then(function (response) { return response.json(); }) - .then(function (result) { - if (result.status.type === "success") - { - // Remove validation class - form.classList.remove("was-validated"); + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + if (result.status.type === "success") { + // Remove validation class + form.classList.remove("was-validated"); - // Close modal - $("#aliasModal").modal("hide"); + // Close modal + $("#aliasModal").modal("hide"); - // Clear modal - piranha.alias.model.id = null; - piranha.alias.model.aliasUrl = null; - piranha.alias.model.redirectUrl = null; - piranha.alias.model.isPermanent = true; + // Clear modal + piranha.alias.model.id = null; + piranha.alias.model.aliasUrl = null; + piranha.alias.model.redirectUrl = null; + piranha.alias.model.isPermanent = true; - piranha.alias.items = result.items; - } + piranha.alias.items = result.items; + } + if (result.status !== 400) { // Push status to notification hub piranha.notifications.push(result.status); - }) - .catch(function (error) { - console.log("error:", error); - }); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } + }) + .catch(function (error) { + console.log("error:", error); + }); }, remove: function (id) { var self = this; @@ -94,17 +96,22 @@ onConfirm: function () { fetch(piranha.baseUrl + "manager/api/alias/delete", { method: "delete", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(id) }) .then(function (response) { return response.json(); }) .then(function (result) { - self.items = result.items; + if (result.status.type === "success") { + self.items = result.items; + } - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error ); }); }
core/Piranha.Manager/assets/dist/js/piranha.alias.min.js+1 −1 modified@@ -1 +1 @@ -piranha.alias=new Vue({el:"#alias",data:{loading:!0,siteId:null,siteTitle:null,sites:[],items:[],model:{id:null,aliasUrl:null,redirectUrl:null,isPermanent:!0}},methods:{load:function(a){var e=this;a||(a=""),fetch(piranha.baseUrl+"manager/api/alias/list/"+a).then(function(a){return a.json()}).then(function(a){e.siteId=a.siteId,e.siteTitle=a.siteTitle,e.sites=a.sites,e.items=a.items}).catch(function(a){console.log("error:",a)})},save:function(){var a=document.getElementById("aliasForm");!1!==a.checkValidity()?fetch(piranha.baseUrl+"manager/api/alias/save",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:piranha.alias.model.id,siteId:piranha.alias.siteId,aliasUrl:piranha.alias.model.aliasUrl,redirectUrl:piranha.alias.model.redirectUrl,isPermanent:null!=piranha.alias.model.isPermanent&&piranha.alias.model.isPermanent})}).then(function(a){return a.json()}).then(function(e){"success"===e.status.type&&(a.classList.remove("was-validated"),$("#aliasModal").modal("hide"),piranha.alias.model.id=null,piranha.alias.model.aliasUrl=null,piranha.alias.model.redirectUrl=null,piranha.alias.model.isPermanent=!0,piranha.alias.items=e.items),piranha.notifications.push(e.status)}).catch(function(a){console.log("error:",a)}):a.classList.add("was-validated")},remove:function(a){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deleteAliasConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/alias/delete",{method:"delete",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}).then(function(a){return a.json()}).then(function(a){e.items=a.items,piranha.notifications.push(a.status)}).catch(function(a){console.log("error:",a)})}})}},updated:function(){this.loading=!1}}),$(document).on("shown.bs.modal","#aliasModal",function(a){$(this).find("#aliasUrl").focus()}); \ No newline at end of file +piranha.alias=new Vue({el:"#alias",data:{loading:!0,siteId:null,siteTitle:null,sites:[],items:[],model:{id:null,aliasUrl:null,redirectUrl:null,isPermanent:!0}},methods:{load:function(a){var i=this;a||(a=""),fetch(piranha.baseUrl+"manager/api/alias/list/"+a).then(function(a){return a.json()}).then(function(a){i.siteId=a.siteId,i.siteTitle=a.siteTitle,i.sites=a.sites,i.items=a.items}).catch(function(a){console.log("error:",a)})},save:function(){var a=document.getElementById("aliasForm");!1!==a.checkValidity()?fetch(piranha.baseUrl+"manager/api/alias/save",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({id:piranha.alias.model.id,siteId:piranha.alias.siteId,aliasUrl:piranha.alias.model.aliasUrl,redirectUrl:piranha.alias.model.redirectUrl,isPermanent:null!=piranha.alias.model.isPermanent&&piranha.alias.model.isPermanent})}).then(function(a){return a.json()}).then(function(i){"success"===i.status.type&&(a.classList.remove("was-validated"),$("#aliasModal").modal("hide"),piranha.alias.model.id=null,piranha.alias.model.aliasUrl=null,piranha.alias.model.redirectUrl=null,piranha.alias.model.isPermanent=!0,piranha.alias.items=i.items),400!==i.status?piranha.notifications.push(i.status):piranha.notifications.unauthorized()}).catch(function(a){console.log("error:",a)}):a.classList.add("was-validated")},remove:function(a){var i=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deleteAliasConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/alias/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(a)}).then(function(a){return a.json()}).then(function(a){"success"===a.status.type&&(i.items=a.items),400!==a.status?piranha.notifications.push(a.status):piranha.notifications.unauthorized()}).catch(function(a){console.log("error:",a)})}})}},updated:function(){this.loading=!1}}),$(document).on("shown.bs.modal","#aliasModal",function(a){$(this).find("#aliasUrl").focus()}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.comment.js+53 −29 modified@@ -44,32 +44,50 @@ piranha.comment = new Vue({ approve: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/comment/approve/" + id + (self.contentId != null ? "/" + self.contentId : "")) - .then(function (response) { return response.json(); }) - .then(function (result) { - if (result.status) { - // Push status to notification hub - piranha.notifications.push(result.status); - } - self.contentId = result.contentId; - self.items = result.comments; + fetch(piranha.baseUrl + "manager/api/comment/approve", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify({ + id: id, + parentId: self.contentId }) - .catch(function (error) { console.log("error:", error ); }); + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + if (result.status) { + // Push status to notification hub + piranha.notifications.push(result.status); + } + self.contentId = result.contentId; + self.items = result.comments; + }) + .catch(function (error) { + console.log("error:", error ); + }); }, unapprove: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/comment/unapprove/" + id + (self.contentId != null ? "/" + self.contentId : "")) - .then(function (response) { return response.json(); }) - .then(function (result) { - if (result.status) { - // Push status to notification hub - piranha.notifications.push(result.status); - } - self.contentId = result.contentId; - self.items = result.comments; + fetch(piranha.baseUrl + "manager/api/comment/unapprove", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify({ + id: id, + parentId: self.contentId }) - .catch(function (error) { console.log("error:", error ); }); + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + if (result.status) { + // Push status to notification hub + piranha.notifications.push(result.status); + } + self.contentId = result.contentId; + self.items = result.comments; + }) + .catch(function (error) { + console.log("error:", error ); + }); }, toggleApproved: function (item) { item.isApproved = !item.isApproved; @@ -83,16 +101,22 @@ piranha.comment = new Vue({ remove: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/comment/delete/" + id) - .then(function (response) { return response.json(); }) - .then(function (result) { - // Push status to notification hub - piranha.notifications.push(result); + fetch(piranha.baseUrl + "manager/api/comment/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + // Push status to notification hub + piranha.notifications.push(result); - // Refresh the list - self.load(self.contentId); - }) - .catch(function (error) { console.log("error:", error ); }); + // Refresh the list + self.load(self.contentId); + }) + .catch(function (error) { + console.log("error:", error ); + }); }, setStatus: function (status) { this.state = status;
core/Piranha.Manager/assets/dist/js/piranha.comment.min.js+1 −1 modified@@ -1 +1 @@ -piranha.comment=new Vue({el:"#comments",data:{loading:!0,contentId:null,items:[],state:"all"},computed:{filteredItems:function(){var n=this;return this.items.filter(function(t){return"all"===n.state||("pending"===n.state?!t.isApproved:t.isApproved)})}},methods:{load:function(n){var t=this;n||(n=""),fetch(piranha.baseUrl+"manager/api/comment/"+n).then(function(n){return n.json()}).then(function(n){t.contentId=n.contentId,t.items=n.comments}).catch(function(n){console.log("error:",n)})},approve:function(n){var t=this;fetch(piranha.baseUrl+"manager/api/comment/approve/"+n+(null!=t.contentId?"/"+t.contentId:"")).then(function(n){return n.json()}).then(function(n){n.status&&piranha.notifications.push(n.status),t.contentId=n.contentId,t.items=n.comments}).catch(function(n){console.log("error:",n)})},unapprove:function(n){var t=this;fetch(piranha.baseUrl+"manager/api/comment/unapprove/"+n+(null!=t.contentId?"/"+t.contentId:"")).then(function(n){return n.json()}).then(function(n){n.status&&piranha.notifications.push(n.status),t.contentId=n.contentId,t.items=n.comments}).catch(function(n){console.log("error:",n)})},toggleApproved:function(n){n.isApproved=!n.isApproved,n.isApproved?this.approve(n.id):this.unapprove(n.id)},remove:function(n){var t=this;fetch(piranha.baseUrl+"manager/api/comment/delete/"+n).then(function(n){return n.json()}).then(function(n){piranha.notifications.push(n),t.load(t.contentId)}).catch(function(n){console.log("error:",n)})},setStatus:function(n){this.state=n}},updated:function(){this.loading=!1}}); \ No newline at end of file +piranha.comment=new Vue({el:"#comments",data:{loading:!0,contentId:null,items:[],state:"all"},computed:{filteredItems:function(){var t=this;return this.items.filter(function(n){return"all"===t.state||("pending"===t.state?!n.isApproved:n.isApproved)})}},methods:{load:function(t){var n=this;t||(t=""),fetch(piranha.baseUrl+"manager/api/comment/"+t).then(function(t){return t.json()}).then(function(t){n.contentId=t.contentId,n.items=t.comments}).catch(function(t){console.log("error:",t)})},approve:function(t){var n=this;fetch(piranha.baseUrl+"manager/api/comment/approve",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({id:t,parentId:n.contentId})}).then(function(t){return t.json()}).then(function(t){t.status&&piranha.notifications.push(t.status),n.contentId=t.contentId,n.items=t.comments}).catch(function(t){console.log("error:",t)})},unapprove:function(t){var n=this;fetch(piranha.baseUrl+"manager/api/comment/unapprove",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({id:t,parentId:n.contentId})}).then(function(t){return t.json()}).then(function(t){t.status&&piranha.notifications.push(t.status),n.contentId=t.contentId,n.items=t.comments}).catch(function(t){console.log("error:",t)})},toggleApproved:function(t){t.isApproved=!t.isApproved,t.isApproved?this.approve(t.id):this.unapprove(t.id)},remove:function(t){var n=this;fetch(piranha.baseUrl+"manager/api/comment/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(t)}).then(function(t){return t.json()}).then(function(t){piranha.notifications.push(t),n.load(n.contentId)}).catch(function(t){console.log("error:",t)})},setStatus:function(t){this.state=t}},updated:function(){this.loading=!1}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.components.js+5 −1 modified@@ -111,7 +111,11 @@ Vue.component("post-archive", { confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/post/delete/" + postId).then(function (response) { + fetch(piranha.baseUrl + "manager/api/post/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(postId) + }).then(function (response) { return response.json(); }).then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/dist/js/piranha.components.min.js+1 −1 modifiedcore/Piranha.Manager/assets/dist/js/piranha.config.js+8 −5 modified@@ -56,9 +56,7 @@ piranha.config = new Vue({ fetch(piranha.baseUrl + "manager/api/config/save", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ hierarchicalPageSlugs: self.model.hierarchicalPageSlugs, expandedSitemapLevels: self.model.expandedSitemapLevels, @@ -80,8 +78,13 @@ piranha.config = new Vue({ }) .then(function (response) { return response.json(); }) .then(function (result) { - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error);
core/Piranha.Manager/assets/dist/js/piranha.config.min.js+1 −1 modified@@ -1 +1 @@ -piranha.config=new Vue({el:"#config",data:{loading:!0,model:{hierarchicalPageSlugs:null,expandedSitemapLevels:null,managerPageSize:null,archivePageSize:null,commentsApprove:null,commentsCloseAfterDays:null,commentsEnabledForPages:null,commentsEnabledForPosts:null,commentsPageSize:null,pagesExpires:null,postsExpires:null,mediaCDN:null,pageRevisions:null,postRevisions:null,defaultCollapsedBlocks:!1,defaultCollapsedBlockGroupHeaders:!1}},methods:{load:function(){self=this,fetch(piranha.baseUrl+"manager/api/config").then(function(e){return e.json()}).then(function(e){self.model.hierarchicalPageSlugs=e.hierarchicalPageSlugs,self.model.expandedSitemapLevels=e.expandedSitemapLevels,self.model.managerPageSize=e.managerPageSize,self.model.archivePageSize=e.archivePageSize,self.model.commentsApprove=e.commentsApprove,self.model.commentsCloseAfterDays=e.commentsCloseAfterDays,self.model.commentsEnabledForPages=e.commentsEnabledForPages,self.model.commentsEnabledForPosts=e.commentsEnabledForPosts,self.model.commentsPageSize=e.commentsPageSize,self.model.pagesExpires=e.pagesExpires,self.model.postsExpires=e.postsExpires,self.model.mediaCDN=e.mediaCDN,self.model.pageRevisions=e.pageRevisions,self.model.postRevisions=e.postRevisions,self.model.defaultCollapsedBlocks=e.defaultCollapsedBlocks,self.model.defaultCollapsedBlockGroupHeaders=e.defaultCollapsedBlockGroupHeaders}).catch(function(e){console.log("error:",e)})},save:function(){self=this,fetch(piranha.baseUrl+"manager/api/config/save",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({hierarchicalPageSlugs:self.model.hierarchicalPageSlugs,expandedSitemapLevels:self.model.expandedSitemapLevels,managerPageSize:self.model.managerPageSize,archivePageSize:self.model.archivePageSize,commentsApprove:self.model.commentsApprove,commentsCloseAfterDays:self.model.commentsCloseAfterDays,commentsEnabledForPages:self.model.commentsEnabledForPages,commentsEnabledForPosts:self.model.commentsEnabledForPosts,commentsPageSize:self.model.commentsPageSize,pagesExpires:self.model.pagesExpires,postsExpires:self.model.postsExpires,mediaCDN:self.model.mediaCDN,pageRevisions:self.model.pageRevisions,postRevisions:self.model.postRevisions,defaultCollapsedBlocks:self.model.defaultCollapsedBlocks,defaultCollapsedBlockGroupHeaders:self.model.defaultCollapsedBlockGroupHeaders})}).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e.status)}).catch(function(e){console.log("error:",e)})}},created:function(){this.load()},updated:function(){this.loading=!1}}); \ No newline at end of file +piranha.config=new Vue({el:"#config",data:{loading:!0,model:{hierarchicalPageSlugs:null,expandedSitemapLevels:null,managerPageSize:null,archivePageSize:null,commentsApprove:null,commentsCloseAfterDays:null,commentsEnabledForPages:null,commentsEnabledForPosts:null,commentsPageSize:null,pagesExpires:null,postsExpires:null,mediaCDN:null,pageRevisions:null,postRevisions:null,defaultCollapsedBlocks:!1,defaultCollapsedBlockGroupHeaders:!1}},methods:{load:function(){self=this,fetch(piranha.baseUrl+"manager/api/config").then(function(e){return e.json()}).then(function(e){self.model.hierarchicalPageSlugs=e.hierarchicalPageSlugs,self.model.expandedSitemapLevels=e.expandedSitemapLevels,self.model.managerPageSize=e.managerPageSize,self.model.archivePageSize=e.archivePageSize,self.model.commentsApprove=e.commentsApprove,self.model.commentsCloseAfterDays=e.commentsCloseAfterDays,self.model.commentsEnabledForPages=e.commentsEnabledForPages,self.model.commentsEnabledForPosts=e.commentsEnabledForPosts,self.model.commentsPageSize=e.commentsPageSize,self.model.pagesExpires=e.pagesExpires,self.model.postsExpires=e.postsExpires,self.model.mediaCDN=e.mediaCDN,self.model.pageRevisions=e.pageRevisions,self.model.postRevisions=e.postRevisions,self.model.defaultCollapsedBlocks=e.defaultCollapsedBlocks,self.model.defaultCollapsedBlockGroupHeaders=e.defaultCollapsedBlockGroupHeaders}).catch(function(e){console.log("error:",e)})},save:function(){self=this,fetch(piranha.baseUrl+"manager/api/config/save",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({hierarchicalPageSlugs:self.model.hierarchicalPageSlugs,expandedSitemapLevels:self.model.expandedSitemapLevels,managerPageSize:self.model.managerPageSize,archivePageSize:self.model.archivePageSize,commentsApprove:self.model.commentsApprove,commentsCloseAfterDays:self.model.commentsCloseAfterDays,commentsEnabledForPages:self.model.commentsEnabledForPages,commentsEnabledForPosts:self.model.commentsEnabledForPosts,commentsPageSize:self.model.commentsPageSize,pagesExpires:self.model.pagesExpires,postsExpires:self.model.postsExpires,mediaCDN:self.model.mediaCDN,pageRevisions:self.model.pageRevisions,postRevisions:self.model.postRevisions,defaultCollapsedBlocks:self.model.defaultCollapsedBlocks,defaultCollapsedBlockGroupHeaders:self.model.defaultCollapsedBlockGroupHeaders})}).then(function(e){return e.json()}).then(function(e){400!==e.status?piranha.notifications.push(e.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})}},created:function(){this.load()},updated:function(){this.loading=!1}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.contentedit.js+6 −4 modified@@ -195,9 +195,7 @@ piranha.contentedit = new Vue({ fetch(route, { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -233,7 +231,11 @@ piranha.contentedit = new Vue({ onConfirm: function () { var groupId = self.groupId; - fetch(piranha.baseUrl + "manager/api/content/delete/" + self.id) + fetch(piranha.baseUrl + "manager/api/content/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/dist/js/piranha.contentedit.min.js+1 −1 modified@@ -1 +1 @@ -piranha.contentedit=new Vue({el:"#contentedit",data:{loading:!0,id:null,languageId:null,typeId:null,typeTitle:null,groupId:null,groupTitle:null,title:null,excerpt:null,state:"new",blocks:[],regions:[],editors:[],categories:[],tags:[],useBlocks:!1,useCategory:!1,useTags:!1,usePrimaryImage:!0,useExcerpt:!0,useHtmlExcerpt:!0,useTranslations:!1,permissions:[],languages:[],primaryImage:{id:null,media:null},selectedPermissions:[],saving:!1,selectedRegion:"",selectedSetting:"uid-settings",selectedCategory:null,selectedTags:[]},computed:{contentRegions:function(){return this.regions.filter(function(e){return"setting"!=e.meta.display&&"hidden"!=e.meta.display})},settingRegions:function(){return this.regions.filter(function(e){return"setting"===e.meta.display})},primaryImageUrl:function(){return null!=this.primaryImage.media?piranha.utils.formatUrl("~/manager/api/media/url/"+this.primaryImage.id+"/448/200"):piranha.utils.formatUrl("~/manager/assets/img/empty-image.png")},isExcerptEmpty:function(){return piranha.utils.isEmptyText(this.excerpt)},currentLanguage:function(){if(null===this.languages)return{id:"",title:""};var e=this;return e.languages.find(function(t){return t.id===e.languageId})}},mounted(){},beforeDestroy(){},methods:{bind:function(e){this.id=e.id,this.languageId=e.languageId,this.typeId=e.typeId,this.typeTitle=e.typeTitle,this.groupId=e.groupId,this.groupTitle=e.groupTitle,this.title=e.title,this.excerpt=e.excerpt,this.state=e.state,this.blocks=e.blocks,this.regions=e.regions,this.editors=e.editors,this.categories=e.categories,this.tags=e.tags,this.languages=e.languages,this.useBlocks=e.useBlocks,this.useCategory=e.useCategory,this.useTags=e.useTags,this.usePrimaryImage=e.usePrimaryImage,this.useExcerpt=e.useExcerpt,this.useHtmlExcerpt=e.useHtmlExcerpt,this.useTranslations=e.useTranslations,this.permissions=e.permissions,this.primaryImage=e.primaryImage,this.selectedPermissions=e.selectedPermissions,this.selectedCategory=e.selectedCategory,this.selectedTags=e.selectedTags,this.useBlocks?this.selectedRegion={uid:"uid-blocks",name:null,icon:null}:this.editors.length>0?this.selectedRegion=this.editors[0]:this.contentRegions.length>0&&(this.selectedRegion=this.contentRegions[0].meta)},load:function(e,t){var i=this,n=piranha.baseUrl+"manager/api/content/"+e;null!=t&&(n+="/"+t),fetch(n).then(function(e){return e.json()}).then(function(e){i.bind(e)}).catch(function(e){console.log("error:",e)})},create:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/content/create/"+e).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},doHotKeys(e){83===e.keyCode&&e.ctrlKey&&(e.preventDefault(),this.save())},save:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/content/save")},saveInternal:function(e){var t=this,i={id:t.id,languageId:t.languageId,typeId:t.typeId,title:t.title,excerpt:t.excerpt,blocks:JSON.parse(JSON.stringify(t.blocks)),regions:JSON.parse(JSON.stringify(t.regions)),selectedRoute:t.selectedRoute,selectedPermissions:t.selectedPermissions,selectedCategory:t.selectedCategory,selectedTags:JSON.parse(JSON.stringify(t.selectedTags)),primaryImage:{id:t.primaryImage.id}};fetch(e,{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){var i=t.state;t.id=e.id,t.state=e.state,t.selectedRoute=e.selectedRoute,"new"===i&&"new"!==e.state&&window.history.replaceState({state:"created"},"Edit content",piranha.baseUrl+"manager/content/edit/"+e.typeId+"/"+e.id),piranha.notifications.push(e.status),t.saving=!1,t.eventBus.$emit("onSaved",t.state)}).catch(function(e){console.log("error:",e)})},remove:function(){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){var t=e.groupId;fetch(piranha.baseUrl+"manager/api/content/delete/"+e.id).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),window.location=piranha.baseUrl+"manager/content/"+t}).catch(function(e){console.log("error:",e)})}})},addBlock:function(e,t){fetch(piranha.baseUrl+"manager/api/content/block/"+e).then(function(e){return e.json()}).then(function(e){piranha.contentedit.blocks.splice(t,0,e.body)}).catch(function(e){console.log("error:",e)})},moveBlock:function(e,t){this.blocks.splice(t,0,this.blocks.splice(e,1)[0])},collapseBlock:function(e){e.meta.isCollapsed=!e.meta.isCollapsed},removeBlock:function(e){var t=this.blocks.indexOf(e);-1!==t&&this.blocks.splice(t,1)},updateBlockTitle:function(e){for(var t=0;t<this.blocks.length;t++)if(this.blocks[t].meta.uid===e.uid){this.blocks[t].meta.title=e.title;break}},selectRegion:function(e){this.selectedRegion=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},selectSetting:function(e){this.selectedSetting=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},selectPrimaryImage:function(){null!==this.primaryImage.media?piranha.mediapicker.open(this.updatePrimaryImage,"Image",this.primaryImage.media.folderId):piranha.mediapicker.openCurrentFolder(this.updatePrimaryImage,"Image")},removePrimaryImage:function(){this.primaryImage.id=null,this.primaryImage.media=null},updatePrimaryImage:function(e){"Image"===e.type?(this.primaryImage.id=e.id,this.primaryImage.media=e):console.log("No image was selected")},onExcerptBlur:function(e){this.useHtmlExcerpt?this.excerpt=tinyMCE.activeEditor.getContent():this.excerpt=e.target.innerHTML}},created:function(){},updated:function(){var e=this;this.loading&&(this.useBlocks&&sortable("#content-blocks",{handle:".handle",items:":not(.unsortable)"})[0].addEventListener("sortupdate",function(t){e.moveBlock(t.detail.origin.index,t.detail.destination.index)}),this.useCategory&&($("#selectedCategory").select2({tags:!0,selectOnClose:!0,placeholder:piranha.resources.texts.addCategory}),$("#selectedCategory").on("change",function(){var t=$(this).find("option:selected").text();e.selectedCategory=t})),this.useTags&&($("#selectedTags").select2({tags:!0,selectOnClose:!1,placeholder:piranha.resources.texts.addTags}),$("#selectedTags").on("change",function(){var t=$(this).find("option:selected");e.selectedTags=[];for(var i=0;i<t.length;i++)e.selectedTags.push(t[i].text)}))),this.loading=!1},components:{datepicker:vuejsDatepicker}}); \ No newline at end of file +piranha.contentedit=new Vue({el:"#contentedit",data:{loading:!0,id:null,languageId:null,typeId:null,typeTitle:null,groupId:null,groupTitle:null,title:null,excerpt:null,state:"new",blocks:[],regions:[],editors:[],categories:[],tags:[],useBlocks:!1,useCategory:!1,useTags:!1,usePrimaryImage:!0,useExcerpt:!0,useHtmlExcerpt:!0,useTranslations:!1,permissions:[],languages:[],primaryImage:{id:null,media:null},selectedPermissions:[],saving:!1,selectedRegion:"",selectedSetting:"uid-settings",selectedCategory:null,selectedTags:[]},computed:{contentRegions:function(){return this.regions.filter(function(e){return"setting"!=e.meta.display&&"hidden"!=e.meta.display})},settingRegions:function(){return this.regions.filter(function(e){return"setting"===e.meta.display})},primaryImageUrl:function(){return null!=this.primaryImage.media?piranha.utils.formatUrl("~/manager/api/media/url/"+this.primaryImage.id+"/448/200"):piranha.utils.formatUrl("~/manager/assets/img/empty-image.png")},isExcerptEmpty:function(){return piranha.utils.isEmptyText(this.excerpt)},currentLanguage:function(){if(null===this.languages)return{id:"",title:""};var e=this;return e.languages.find(function(t){return t.id===e.languageId})}},mounted(){},beforeDestroy(){},methods:{bind:function(e){this.id=e.id,this.languageId=e.languageId,this.typeId=e.typeId,this.typeTitle=e.typeTitle,this.groupId=e.groupId,this.groupTitle=e.groupTitle,this.title=e.title,this.excerpt=e.excerpt,this.state=e.state,this.blocks=e.blocks,this.regions=e.regions,this.editors=e.editors,this.categories=e.categories,this.tags=e.tags,this.languages=e.languages,this.useBlocks=e.useBlocks,this.useCategory=e.useCategory,this.useTags=e.useTags,this.usePrimaryImage=e.usePrimaryImage,this.useExcerpt=e.useExcerpt,this.useHtmlExcerpt=e.useHtmlExcerpt,this.useTranslations=e.useTranslations,this.permissions=e.permissions,this.primaryImage=e.primaryImage,this.selectedPermissions=e.selectedPermissions,this.selectedCategory=e.selectedCategory,this.selectedTags=e.selectedTags,this.useBlocks?this.selectedRegion={uid:"uid-blocks",name:null,icon:null}:this.editors.length>0?this.selectedRegion=this.editors[0]:this.contentRegions.length>0&&(this.selectedRegion=this.contentRegions[0].meta)},load:function(e,t){var i=this,s=piranha.baseUrl+"manager/api/content/"+e;null!=t&&(s+="/"+t),fetch(s).then(function(e){return e.json()}).then(function(e){i.bind(e)}).catch(function(e){console.log("error:",e)})},create:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/content/create/"+e).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},doHotKeys(e){83===e.keyCode&&e.ctrlKey&&(e.preventDefault(),this.save())},save:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/content/save")},saveInternal:function(e){var t=this,i={id:t.id,languageId:t.languageId,typeId:t.typeId,title:t.title,excerpt:t.excerpt,blocks:JSON.parse(JSON.stringify(t.blocks)),regions:JSON.parse(JSON.stringify(t.regions)),selectedRoute:t.selectedRoute,selectedPermissions:t.selectedPermissions,selectedCategory:t.selectedCategory,selectedTags:JSON.parse(JSON.stringify(t.selectedTags)),primaryImage:{id:t.primaryImage.id}};fetch(e,{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){var i=t.state;t.id=e.id,t.state=e.state,t.selectedRoute=e.selectedRoute,"new"===i&&"new"!==e.state&&window.history.replaceState({state:"created"},"Edit content",piranha.baseUrl+"manager/content/edit/"+e.typeId+"/"+e.id),piranha.notifications.push(e.status),t.saving=!1,t.eventBus.$emit("onSaved",t.state)}).catch(function(e){console.log("error:",e)})},remove:function(){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){var t=e.groupId;fetch(piranha.baseUrl+"manager/api/content/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),window.location=piranha.baseUrl+"manager/content/"+t}).catch(function(e){console.log("error:",e)})}})},addBlock:function(e,t){fetch(piranha.baseUrl+"manager/api/content/block/"+e).then(function(e){return e.json()}).then(function(e){piranha.contentedit.blocks.splice(t,0,e.body)}).catch(function(e){console.log("error:",e)})},moveBlock:function(e,t){this.blocks.splice(t,0,this.blocks.splice(e,1)[0])},collapseBlock:function(e){e.meta.isCollapsed=!e.meta.isCollapsed},removeBlock:function(e){var t=this.blocks.indexOf(e);-1!==t&&this.blocks.splice(t,1)},updateBlockTitle:function(e){for(var t=0;t<this.blocks.length;t++)if(this.blocks[t].meta.uid===e.uid){this.blocks[t].meta.title=e.title;break}},selectRegion:function(e){this.selectedRegion=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},selectSetting:function(e){this.selectedSetting=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},selectPrimaryImage:function(){null!==this.primaryImage.media?piranha.mediapicker.open(this.updatePrimaryImage,"Image",this.primaryImage.media.folderId):piranha.mediapicker.openCurrentFolder(this.updatePrimaryImage,"Image")},removePrimaryImage:function(){this.primaryImage.id=null,this.primaryImage.media=null},updatePrimaryImage:function(e){"Image"===e.type?(this.primaryImage.id=e.id,this.primaryImage.media=e):console.log("No image was selected")},onExcerptBlur:function(e){this.useHtmlExcerpt?this.excerpt=tinyMCE.activeEditor.getContent():this.excerpt=e.target.innerHTML}},created:function(){},updated:function(){var e=this;this.loading&&(this.useBlocks&&sortable("#content-blocks",{handle:".handle",items:":not(.unsortable)"})[0].addEventListener("sortupdate",function(t){e.moveBlock(t.detail.origin.index,t.detail.destination.index)}),this.useCategory&&($("#selectedCategory").select2({tags:!0,selectOnClose:!0,placeholder:piranha.resources.texts.addCategory}),$("#selectedCategory").on("change",function(){var t=$(this).find("option:selected").text();e.selectedCategory=t})),this.useTags&&($("#selectedTags").select2({tags:!0,selectOnClose:!1,placeholder:piranha.resources.texts.addTags}),$("#selectedTags").on("change",function(){var t=$(this).find("option:selected");e.selectedTags=[];for(var i=0;i<t.length;i++)e.selectedTags.push(t[i].text)}))),this.loading=!1},components:{datepicker:vuejsDatepicker}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.contentlist.js+5 −1 modified@@ -49,7 +49,11 @@ piranha.contentlist = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/content/delete/" + id) + fetch(piranha.baseUrl + "manager/api/content/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/dist/js/piranha.contentlist.min.js+1 −1 modified@@ -1 +1 @@ -piranha.contentlist=new Vue({el:"#contentlist",data:{loading:!0,group:null,items:[],types:[]},methods:{bind:function(n){this.group=n.group,this.types=n.types,this.items=n.items.map(function(t){var e=n.types.find(function(n){return n.id===t.typeId});return t.type=e.title||t.typeId,t})},load:function(n){var t=this;piranha.permissions.load(function(){fetch(piranha.baseUrl+"manager/api/content/"+n+"/list").then(function(n){return n.json()}).then(function(n){t.bind(n),t.loading=!1}).catch(function(n){console.log("error:",n)})})},remove:function(n){var t=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/content/delete/"+n).then(function(n){return n.json()}).then(function(n){piranha.notifications.push(n),t.load(t.group.id)}).catch(function(n){console.log("error:",n)})}})}},created:function(){}}); \ No newline at end of file +piranha.contentlist=new Vue({el:"#contentlist",data:{loading:!0,group:null,items:[],types:[]},methods:{bind:function(n){this.group=n.group,this.types=n.types,this.items=n.items.map(function(t){var e=n.types.find(function(n){return n.id===t.typeId});return t.type=e.title||t.typeId,t})},load:function(n){var t=this;piranha.permissions.load(function(){fetch(piranha.baseUrl+"manager/api/content/"+n+"/list").then(function(n){return n.json()}).then(function(n){t.bind(n),t.loading=!1}).catch(function(n){console.log("error:",n)})})},remove:function(n){var t=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/content/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(n)}).then(function(n){return n.json()}).then(function(n){piranha.notifications.push(n),t.load(t.group.id)}).catch(function(n){console.log("error:",n)})}})}},created:function(){}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.js+61 −23 modified@@ -155,6 +155,7 @@ piranha.dropzone = new function () { var defaultOptions = { paramName: 'Uploads', url: piranha.baseUrl + "manager/api/media/upload", + headers: piranha.utils.antiForgeryHeaders(false), thumbnailWidth: 70, thumbnailHeight: 70, previewsContainer: selector + " .media-list", @@ -296,7 +297,28 @@ piranha.utils = { }, strLength: function (str) { return str != null ? str.length : 0; - } + }, + antiForgery: function () { + const cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) { + let c = cookies[i].trim().split("="); + if (c[0] === piranha.antiForgery.cookieName) { + return c[1]; + } + } + return ""; + }, + antiForgeryHeaders: function (isJson) { + var headers = {}; + + if (isJson === undefined || isJson === true) + { + headers["Content-Type"] = "application/json"; + } + headers[piranha.antiForgery.headerName] = piranha.utils.antiForgery(); + + return headers; + } }; Date.prototype.addDays = function(days) { @@ -479,6 +501,13 @@ piranha.notifications = new Vue({ items: [], }, methods: { + unauthorized: function() { + this.push({ + type: "danger", + body: "Request sender could not be verified by the server.", + hide: true + }); + }, push: function (notification) { notification.style = { @@ -753,9 +782,7 @@ piranha.mediapicker = new Vue({ if (self.folderName !== "") { fetch(piranha.baseUrl + "manager/api/media/folder/save" + (self.filter ? "?filter=" + self.filter : ""), { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ parentId: self.currentFolderId, name: self.folderName @@ -772,8 +799,13 @@ piranha.mediapicker = new Vue({ self.items = result.media; } - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); @@ -1123,22 +1155,25 @@ piranha.languageedit = new Vue({ self.loading = true; fetch(piranha.baseUrl + "manager/api/language", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ items: JSON.parse(JSON.stringify(self.items)) }) }) .then(function (response) { return response.json(); }) .then(function (result) { - //if (result.status.type === "success") - //{ + if (result.status.type === "success") { self.bind(result); - //} - - // Push status to notification hub - // piranha.notifications.push(result.status); + } + + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + self.loading = false; + } }) .catch(function (error) { console.log("error:", error); @@ -1151,20 +1186,23 @@ piranha.languageedit = new Vue({ self.loading = true; fetch(piranha.baseUrl + "manager/api/language/" + item.id, { method: "delete", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(item) }) .then(function (response) { return response.json(); }) .then(function (result) { - //if (result.status.type === "success") - //{ + if (result.status.type === "success") { self.bind(result); - //} + } - // Push status to notification hub - // piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + self.loading = false; + } }) .catch(function (error) { console.log("error:", error);
core/Piranha.Manager/assets/dist/js/piranha.media.js+52 −31 modified@@ -119,18 +119,22 @@ piranha.media = new Vue({ fetch(piranha.baseUrl + "manager/api/media/move/" + (folderId || ""), { method: "POST", - headers: { - 'Content-Type': 'application/json' - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(selections) }) .then(function (response) { return response.json(); }) .then(function (result) { if (result.type === "success") { piranha.media.refresh(); } - // Push status to notification hub - piranha.notifications.push(result); + + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); }); }, @@ -170,7 +174,6 @@ piranha.media = new Vue({ piranha.media.load(piranha.media.currentFolderId); }, addFolder: function () { - //this.saveFolder("#mediaFolderModal", "mediaFolderForm", { this.saveFolder(null, null, { parentId: this.currentFolderId, name: this.folder.name @@ -197,9 +200,7 @@ piranha.media = new Vue({ fetch(piranha.baseUrl + "manager/api/media/folder/save", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(folder) }) .then(function (response) { return response.json(); }) @@ -219,8 +220,13 @@ piranha.media = new Vue({ self.refresh(); } - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); @@ -230,19 +236,22 @@ piranha.media = new Vue({ var self = this; fetch(piranha.baseUrl + "manager/api/media/delete", { - method: "post", - headers: { - "Content-Type": "application/json", - }, + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify([id]) }) .then(function (response) { return response.json(); }) .then(function (result) { // Refresh self.refresh(); - // Push status to notification hub - piranha.notifications.push(result); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error ); }); }, @@ -258,19 +267,22 @@ piranha.media = new Vue({ confirmText: piranha.resources.texts.delete, onConfirm: function () { fetch(piranha.baseUrl + "manager/api/media/delete", { - method: "post", - headers: { - "Content-Type": "application/json", - }, + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(selections) }) .then(function (response) { return response.json(); }) .then(function (result) { // Refresh self.refresh(); - // Push status to notification hub - piranha.notifications.push(result); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); }); } @@ -279,18 +291,27 @@ piranha.media = new Vue({ removeFolder: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/media/folder/delete/" + id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/media/folder/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - history.pushState({ folderId: id }, "", piranha.baseUrl + "manager/media" + (id ? "/" + id : "")); - document.title = result.currentFolderName ? result.currentFolderName : "Media"; + history.pushState({ folderId: id }, "", piranha.baseUrl + "manager/media" + (id ? "/" + id : "")); + document.title = result.currentFolderName ? result.currentFolderName : "Media"; + if (result.status !== 400) { // Push status to notification hub piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); }); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } + }) + .catch(function (error) { console.log("error:", error ); }); } }, computed: {
core/Piranha.Manager/assets/dist/js/piranha.media.min.js+1 −1 modified@@ -1 +1 @@ -Vue.component("folder-item",{props:["item","selected"],template:'\n<li class="dd-item expanded" :class="{ active: item.id === selected, expanded: item.isExpanded || item.items.length === 0 }" :data-id="item.id">\n <a v-if="!item.edit" class="droppable" v-on:click.prevent="piranha.media.load(item.id)" href="#" draggable="true" v-on:dragstart="piranha.media.drag($event, item)" v-on:dragover="piranha.media.dragover" v-on:dragleave="piranha.media.dragleave" v-on:drop="piranha.media.drop($event, item.id)">\n <i class="fas fa-folder"></i>{{ item.name }}\n <span class="badge badge-light float-right">{{ item.mediaCount }}</span>\n </a>\n <form v-else v-on:submit.prevent="piranha.media.updateFolder()" class="d-flex">\n <i class="fas fa-folder"></i>\n <input :id="\'folder-\' + item.id" type="text" v-on:keyup.esc="piranha.media.cancelEditFolder()" v-model="piranha.media.currentFolderName" class="form-control form-control-sm">\n </form>\n <ol v-if="selected === item.id && piranha.media.isAdding" class="dd-list">\n <form v-on:submit.prevent="piranha.media.addFolder()" class="d-flex">\n <i class="fas fa-folder"></i><input id="add-folder" type="text" v-on:keyup.esc="piranha.media.isAdding = false" v-model="piranha.media.folder.name" class="form-control form-control-sm">\n </form>\n </ol>\n <ol v-if="item.items.length > 0" class="dd-list">\n <folder-item v-for="child in item.items" v-bind:key="child.id" v-bind:selected="selected" v-bind:item="child"></folder-item>\n </ol>\n</li>\n'}),piranha.media=new Vue({el:"#media",data:{loading:!0,listView:!0,currentFolder:null,currentFolderId:null,currentFolderName:null,parentFolderId:null,folders:[],items:[],structure:[],rootCount:null,totalCount:null,canDelete:!1,isAdding:!1,newFolderName:null,folder:{name:null},dropzone:null},methods:{bind:function(e){this.currentFolderId=e.currentFolderId,this.currentFolderName=e.currentFolderName,this.parentFolderId=e.parentFolderId,this.initFolders(e.structure),this.folders=e.folders,this.items=e.media.map(function(e){return e.selected=!1,e}),this.structure=e.structure,this.rootCount=e.rootCount,this.totalCount=e.totalCount,this.canDelete=e.canDelete,this.listView="list"===e.viewMode},initFolders:function(e){for(var t=0;t<e.length;t++)e[t].edit=!1,e[t].id===this.currentFolderId&&(this.currentFolder=e[t]),e[t].items.length>0&&this.initFolders(e[t].items)},editFolder:function(){this.currentFolder.edit=!0,this.$nextTick(function(){document.getElementById("folder-"+this.currentFolderId).focus()})},editAddFolder:function(){this.isAdding=!0,this.$nextTick(function(){document.getElementById("add-folder").focus()})},cancelEditFolder:function(){this.currentFolder.edit=!1,this.currentFolderName=this.currentFolder.name},drag:function(e,t){e.dataTransfer.setData("mediaId",t.id)},dragover:function(e){e.preventDefault();var t=$(e.target).closest(".droppable");t.hasClass("active")||t.addClass("active")},dragleave:function(e){e.preventDefault();var t=$(e.target).closest(".droppable");t.hasClass("active")&&t.removeClass("active")},drop:function(e,t){e.preventDefault();var n=$(e.target).closest(".droppable");n.hasClass("active")&&n.removeClass("active");var i=e.dataTransfer.getData("mediaId");if(i!==t){var a=this.items.filter(e=>e.selected).map(e=>e.id);a.includes(i)||(a=[]).push(i),fetch(piranha.baseUrl+"manager/api/media/move/"+(t||""),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}).then(function(e){return e.json()}).then(function(e){"success"===e.type&&piranha.media.refresh(),piranha.notifications.push(e)}).catch(function(e){console.log("error:",e)})}},onItemClick:function(e,t){e.shiftKey?t.selected=!t.selected:piranha.preview.openItem(t)},showList:function(){this.listView=!0},showGallery:function(){this.listView=!1},load:function(e,t){var n=this;t||history.pushState({folderId:e},"",piranha.baseUrl+"manager/media"+(e?"/"+e:"")),fetch(piranha.baseUrl+"manager/api/media/list"+(e?"/"+e:"")+"/?width=210&height=160").then(function(e){return e.json()}).then(function(e){n.bind(e),document.title=e.currentFolderName?e.currentFolderName:"Media"}).catch(function(e){console.log("error:",e)})},getThumbnailUrl:function(e){return null!==e.altVersionUrl?e.altVersionUrl:piranha.baseUrl+"manager/api/media/url/"+e.id+"/210/160"},refresh:function(){piranha.media.load(piranha.media.currentFolderId)},addFolder:function(){this.saveFolder(null,null,{parentId:this.currentFolderId,name:this.folder.name}),this.isAdding=!1},updateFolder:function(){this.saveFolder(null,null,{id:this.currentFolderId,name:this.currentFolderName})},saveFolder:function(e,t,n){var i=this;if(null!=t&&!1===(t=document.getElementById(t)).checkValidity())return void t.classList.add("was-validated");fetch(piranha.baseUrl+"manager/api/media/folder/save",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)}).then(function(e){return e.json()}).then(function(t){"success"===t.status.type&&(null!=e&&$(e).modal("hide"),i.folder.name=null,i.items=t.media,i.refresh()),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},remove:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/media/delete",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify([e])}).then(function(e){return e.json()}).then(function(e){t.refresh(),piranha.notifications.push(e)}).catch(function(e){console.log("error:",e)})},removeSelection:function(){var e=this,t=this.items.filter(e=>e.selected).map(e=>e.id);piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deleteMediaSelectionConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/media/delete",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(function(e){return e.json()}).then(function(t){e.refresh(),piranha.notifications.push(t)}).catch(function(e){console.log("error:",e)})}})},removeFolder:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/media/folder/delete/"+e).then(function(e){return e.json()}).then(function(n){t.bind(n),history.pushState({folderId:e},"",piranha.baseUrl+"manager/media"+(e?"/"+e:"")),document.title=n.currentFolderName?n.currentFolderName:"Media",piranha.notifications.push(n.status)}).catch(function(e){console.log("error:",e)})}},computed:{hasSelection:function(){return this.items.some(function(e){return e.selected})}},updated:function(){this.loading&&(piranha.permissions.media.add&&(this.dropzone=piranha.dropzone.init("#media-upload-container",{uploadMultiple:!1}),this.dropzone.on("complete",function(e){"success"===e.status&&setTimeout(function(){piranha.media.dropzone.removeFile(e)},3e3)}),this.dropzone.on("queuecomplete",function(){piranha.media.refresh()})),this.loading=!1)},mounted:function(){var e=this;window.onpopstate=function(t){e.load(t.state&&t.state.folderId?t.state.folderId:"",!0)}}}),$(document).on("shown.bs.modal","#mediaFolderModal",function(e){$("#mediaFolderName").focus()}); \ No newline at end of file +Vue.component("folder-item",{props:["item","selected"],template:'\n<li class="dd-item expanded" :class="{ active: item.id === selected, expanded: item.isExpanded || item.items.length === 0 }" :data-id="item.id">\n <a v-if="!item.edit" class="droppable" v-on:click.prevent="piranha.media.load(item.id)" href="#" draggable="true" v-on:dragstart="piranha.media.drag($event, item)" v-on:dragover="piranha.media.dragover" v-on:dragleave="piranha.media.dragleave" v-on:drop="piranha.media.drop($event, item.id)">\n <i class="fas fa-folder"></i>{{ item.name }}\n <span class="badge badge-light float-right">{{ item.mediaCount }}</span>\n </a>\n <form v-else v-on:submit.prevent="piranha.media.updateFolder()" class="d-flex">\n <i class="fas fa-folder"></i>\n <input :id="\'folder-\' + item.id" type="text" v-on:keyup.esc="piranha.media.cancelEditFolder()" v-model="piranha.media.currentFolderName" class="form-control form-control-sm">\n </form>\n <ol v-if="selected === item.id && piranha.media.isAdding" class="dd-list">\n <form v-on:submit.prevent="piranha.media.addFolder()" class="d-flex">\n <i class="fas fa-folder"></i><input id="add-folder" type="text" v-on:keyup.esc="piranha.media.isAdding = false" v-model="piranha.media.folder.name" class="form-control form-control-sm">\n </form>\n </ol>\n <ol v-if="item.items.length > 0" class="dd-list">\n <folder-item v-for="child in item.items" v-bind:key="child.id" v-bind:selected="selected" v-bind:item="child"></folder-item>\n </ol>\n</li>\n'}),piranha.media=new Vue({el:"#media",data:{loading:!0,listView:!0,currentFolder:null,currentFolderId:null,currentFolderName:null,parentFolderId:null,folders:[],items:[],structure:[],rootCount:null,totalCount:null,canDelete:!1,isAdding:!1,newFolderName:null,folder:{name:null},dropzone:null},methods:{bind:function(e){this.currentFolderId=e.currentFolderId,this.currentFolderName=e.currentFolderName,this.parentFolderId=e.parentFolderId,this.initFolders(e.structure),this.folders=e.folders,this.items=e.media.map(function(e){return e.selected=!1,e}),this.structure=e.structure,this.rootCount=e.rootCount,this.totalCount=e.totalCount,this.canDelete=e.canDelete,this.listView="list"===e.viewMode},initFolders:function(e){for(var t=0;t<e.length;t++)e[t].edit=!1,e[t].id===this.currentFolderId&&(this.currentFolder=e[t]),e[t].items.length>0&&this.initFolders(e[t].items)},editFolder:function(){this.currentFolder.edit=!0,this.$nextTick(function(){document.getElementById("folder-"+this.currentFolderId).focus()})},editAddFolder:function(){this.isAdding=!0,this.$nextTick(function(){document.getElementById("add-folder").focus()})},cancelEditFolder:function(){this.currentFolder.edit=!1,this.currentFolderName=this.currentFolder.name},drag:function(e,t){e.dataTransfer.setData("mediaId",t.id)},dragover:function(e){e.preventDefault();var t=$(e.target).closest(".droppable");t.hasClass("active")||t.addClass("active")},dragleave:function(e){e.preventDefault();var t=$(e.target).closest(".droppable");t.hasClass("active")&&t.removeClass("active")},drop:function(e,t){e.preventDefault();var n=$(e.target).closest(".droppable");n.hasClass("active")&&n.removeClass("active");var i=e.dataTransfer.getData("mediaId");if(i!==t){var a=this.items.filter(e=>e.selected).map(e=>e.id);a.includes(i)||(a=[]).push(i),fetch(piranha.baseUrl+"manager/api/media/move/"+(t||""),{method:"POST",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(a)}).then(function(e){return e.json()}).then(function(e){"success"===e.type&&piranha.media.refresh(),400!==e.status?piranha.notifications.push(e.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})}},onItemClick:function(e,t){e.shiftKey?t.selected=!t.selected:piranha.preview.openItem(t)},showList:function(){this.listView=!0},showGallery:function(){this.listView=!1},load:function(e,t){var n=this;t||history.pushState({folderId:e},"",piranha.baseUrl+"manager/media"+(e?"/"+e:"")),fetch(piranha.baseUrl+"manager/api/media/list"+(e?"/"+e:"")+"/?width=210&height=160").then(function(e){return e.json()}).then(function(e){n.bind(e),document.title=e.currentFolderName?e.currentFolderName:"Media"}).catch(function(e){console.log("error:",e)})},getThumbnailUrl:function(e){return null!==e.altVersionUrl?e.altVersionUrl:piranha.baseUrl+"manager/api/media/url/"+e.id+"/210/160"},refresh:function(){piranha.media.load(piranha.media.currentFolderId)},addFolder:function(){this.saveFolder(null,null,{parentId:this.currentFolderId,name:this.folder.name}),this.isAdding=!1},updateFolder:function(){this.saveFolder(null,null,{id:this.currentFolderId,name:this.currentFolderName})},saveFolder:function(e,t,n){var i=this;if(null!=t&&!1===(t=document.getElementById(t)).checkValidity())return void t.classList.add("was-validated");fetch(piranha.baseUrl+"manager/api/media/folder/save",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(n)}).then(function(e){return e.json()}).then(function(t){"success"===t.status.type&&(null!=e&&$(e).modal("hide"),i.folder.name=null,i.items=t.media,i.refresh()),400!==t.status?piranha.notifications.push(t.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})},remove:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/media/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify([e])}).then(function(e){return e.json()}).then(function(e){t.refresh(),400!==e.status?piranha.notifications.push(e.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})},removeSelection:function(){var e=this,t=this.items.filter(e=>e.selected).map(e=>e.id);piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deleteMediaSelectionConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/media/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(t)}).then(function(e){return e.json()}).then(function(t){e.refresh(),400!==t.status?piranha.notifications.push(t.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})}})},removeFolder:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/media/folder/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e)}).then(function(e){return e.json()}).then(function(n){t.bind(n),history.pushState({folderId:e},"",piranha.baseUrl+"manager/media"+(e?"/"+e:"")),document.title=n.currentFolderName?n.currentFolderName:"Media",400!==n.status?piranha.notifications.push(n.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})}},computed:{hasSelection:function(){return this.items.some(function(e){return e.selected})}},updated:function(){this.loading&&(piranha.permissions.media.add&&(this.dropzone=piranha.dropzone.init("#media-upload-container",{uploadMultiple:!1}),this.dropzone.on("complete",function(e){"success"===e.status&&setTimeout(function(){piranha.media.dropzone.removeFile(e)},3e3)}),this.dropzone.on("queuecomplete",function(){piranha.media.refresh()})),this.loading=!1)},mounted:function(){var e=this;window.onpopstate=function(t){e.load(t.state&&t.state.folderId?t.state.folderId:"",!0)}}}),$(document).on("shown.bs.modal","#mediaFolderModal",function(e){$("#mediaFolderName").focus()}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.min.js+1 −1 modified@@ -1 +1 @@ -Vue.prototype.eventBus=new Vue,piranha.accessibility=new function(){"use strict";var e=this;e.focus=null,e.removeBlock=function(e){var t=$(":focus").parents(".block");if(1===t.length){if(tinymce){var i=tinymce.activeEditor;i&&i.inline&&i.destroy()}t.find(".block-remove").click()}},$(document).on("show.bs.modal",".modal",function(){e.focus=$(":focus")}),$(document).on("hidden.bs.modal",".modal",function(){e.focus&&(e.focus.focus(),e.focus=null)}),$(window).on("keydown",function(t){$(".main-nav");t.altKey&&(67===t.keyCode?$("#contentSelector").click():8===t.keyCode&&e.removeBlock(t))})},piranha.alert=new Vue({el:"#alert",data:{title:null,body:null,confirmCss:null,confirmIcon:null,confirmText:null,cancelCss:null,cancelIcon:null,cancelText:null,onConfirm:null,onCancel:null,verifyPhrase:null,verifyPlaceholder:null,verifyText:null,verifyInput:null},methods:{open:function(e){e&&(this.title=e.title,this.body=e.body,this.confirmCss=e.confirmCss?e.confirmCss:"btn-success",this.confirmIcon=e.confirmIcon,this.confirmText=e.confirmText?e.confirmText:piranha.resources.texts.ok,this.cancelCss=e.cancelCss?e.cancelCss:"btn-secondary",this.cancelIcon=e.cancelIcon,this.cancelText=e.cancelText?e.cancelText:piranha.resources.texts.cancel,this.onConfirm=e.onConfirm,this.onCancel=e.onCancel,this.verifyPhrase=e.verifyPhrase,this.verifyPlaceholder=e.verifyPlaceholder,this.verifyText=e.verifyText,$("#alert").modal("show"))},confirm:function(){this.onConfirm&&(this.onConfirm(),this.clear()),$("#alert").modal("hide")},cancel:function(){this.onCancel&&(this.onCancel(),this.clear()),$("#alert").modal("hide")},canConfirm:function(){return!this.verifyPhrase||this.verifyPhrase===this.verifyInput},clear:function(){this.onCancel=null,this.onConfirm=null,this.verifyInput=null}}}),Dropzone.autoDiscover=!1,piranha.dropzone=new function(){this.init=function(e,t){t||(t={});var i={paramName:"Uploads",url:piranha.baseUrl+"manager/api/media/upload",thumbnailWidth:70,thumbnailHeight:70,previewsContainer:e+" .media-list",previewTemplate:document.querySelector("#media-upload-template").innerHTML,uploadMultiple:!0,init:function(){t.addedfile||(t.addedfile=function(e){}),t.removedfile||(t.removedfile=function(e){}),t.error||(t.error=function(e){}),t.complete||(t.complete=function(e){if("success"!==e.status&&""!==e.xhr.responseText){var t=JSON.parse(e.xhr.responseText);e.previewElement.querySelector("[data-dz-errormessage]").innerText=t.body}}),t.queuecomplete||(t.queuecomplete=function(){}),this.on("addedfile",t.addedfile),this.on("removedfile",t.removedfile),this.on("complete",t.complete),this.on("queuecomplete",t.queuecomplete)}},n=Object.assign(i,t);return new Dropzone(e+" form",n)}},piranha.permissions={loaded:!1,aliases:{edit:!1,delete:!1},comments:{approve:!1,delete:!1},media:{add:!1,addFolder:!1,delete:!1,deleteFolder:!1,edit:!1},pages:{add:!1,delete:!1,edit:!1,preview:!1,publish:!1,save:!1},posts:{add:!1,delete:!1,edit:!1,preview:!1,publish:!1,save:!1},sites:{add:!1,delete:!1,edit:!1,save:!1},load:function(e){var t=this;this.loaded?e&&e():fetch(piranha.baseUrl+"manager/api/permissions").then(function(e){return e.json()}).then(function(i){t.aliases=i.aliases,t.comments=i.comments,t.media=i.media,t.pages=i.pages,t.posts=i.posts,t.sites=i.sites,t.loaded=!0,e&&e()}).catch(function(t){console.log("error:",t),e&&e()})}},piranha.utils={formatUrl:function(e){return e.replace("~/",piranha.baseUrl)},isEmptyHtml:function(e){return null==e||""==e.replace(/(<([^>]+)>)/gi,"").replace(/\s/g,"")&&-1===e.indexOf("<img")},isEmptyText:function(e){return null==e||""==e.replace(/\s/g,"")||"<br>"==e.replace(/\s/g,"")},strLength:function(e){return null!=e?e.length:0}},Date.prototype.addDays=function(e){var t=new Date(this.valueOf());return t.setDate(t.getDate()+e),t},Date.prototype.toDateString=function(e){var t=new Date(this.valueOf());return t.getFullYear()+"-"+String(t.getMonth()+1).padStart(2,"0")+"-"+String(t.getDate()).padStart(2,"0")},$(document).ready(function(){$(".block-header .danger").hover(function(){$(this).closest(".block").addClass("danger")},function(){$(this).closest(".block").removeClass("danger")}),$("form.validate").submit(function(e){!1===$(this).get(0).checkValidity()&&(e.preventDefault(),e.stopPropagation(),$(this).addClass("was-validated"))})}),$(document).on("mouseenter",".block-header .danger",function(){$(this).closest(".block").addClass("danger")}),$(document).on("mouseleave",".block-header .danger",function(){$(this).closest(".block").removeClass("danger")}),$(document).on("shown.bs.collapse",".collapse",function(){$(this).parent().addClass("active")}),$(document).on("hide.bs.collapse",".collapse",function(){$(this).parent().removeClass("active")}),$(document).on("hidden.bs.modal",".modal",function(){$(".modal:visible").length&&$(document.body).addClass("modal-open")}),$(window).scroll(function(){var e=$(this).scrollTop();$(".app .component-toolbar").each(function(){var t=$(this).parent(),i=t.offset().top;if(e>i){var n=t.outerHeight();e>i+n?$(this).css({top:n+"px"}):$(this).css({top:e-i+"px"})}else $(this).removeAttr("style")})}),piranha.blockpicker=new Vue({el:"#blockpicker",data:{filter:"",categories:[],index:0,callback:null},computed:{filteredCategories:function(){var e=this;return this.categories.filter(function(t){return e.filterBlockTypes(t).length>0})}},methods:{open:function(e,t,i){var n=this,r=piranha.baseUrl+"manager/api/content/blocktypes";piranha.pageedit?r+="/page/"+piranha.pageedit.typeId:piranha.postedit&&(r+="/post/"+piranha.postedit.typeId),fetch(r+(null!=i?"/"+i:"")).then(function(e){return e.json()}).then(function(i){i.typeCount>1?(n.filter="",n.index=t,n.callback=e,n.categories=i.categories,$("#blockpicker").modal("show")):e(i.categories[0].items[0].type,t)}).catch(function(e){console.log("error:",e)})},select:function(e){this.callback(e.type,this.index),this.index=0,this.callback=null,$("#blockpicker").modal("hide")},selectSingleItem:function(){var e=this.filteredCategories;if(1===e.length){var t=this.filterBlockTypes(e[0]);1===t.length&&this.select(t[0])}},filterBlockTypes:function(e){var t=this;return e.items.filter(function(e){return e.name.toLowerCase().indexOf(t.filter.toLowerCase())>-1})}},created:function(){}}),$(document).ready(function(){$("#blockpicker").on("shown.bs.modal",function(){$("#blockpickerSearch").trigger("focus")})}),piranha.notifications=new Vue({el:"#notification-hub",data:{items:[]},methods:{push:function(e){e.style={visible:!1,"notification-info":"info"===e.type,"notification-danger":"danger"===e.type,"notification-success":"success"===e.type,"notification-warning":"warning"===e.type},piranha.notifications.items.push(e),setTimeout(function(){e.style.visible=!0,e.hide&&setTimeout(function(){e.style.visible=!1,setTimeout(function(){piranha.notifications.items.shift()},200)},5e3)},200)}}}),piranha.contentpicker=new Vue({el:"#contentpicker",data:{search:"",groups:[],items:[],currentGroupId:null,currentGroupTitle:null,currentGroupIcon:null,filter:null,callback:null},computed:{filteredItems:function(){var e=this;return this.items.filter(function(t){return!(e.search.length>0)||t.title.toLowerCase().indexOf(e.search.toLowerCase())>-1})}},methods:{bind:function(e,t){this.currentGroupId=e.group.id,this.currentGroupTitle=e.group.title,this.currentGroupIcon=e.group.icon,this.types=e.types,this.items=e.items.map(function(t){var i=e.types.find(function(e){return e.id===t.typeId});return t.type=i.title||t.typeId,t}),t||(this.groups=e.groups)},load:function(e,t){var i=piranha.baseUrl+"manager/api/content/"+(e?e+"/":"")+"list",n=this;fetch(i).then(function(e){return e.json()}).then(function(e){n.bind(e,t)}).catch(function(e){console.log("error:",e)})},loadGroups:function(){},refresh:function(){this.load(piranha.contentpicker.currentGroupId,!0)},open:function(e,t){this.search="",this.callback=t,this.load(e),$("#contentpicker").modal("show")},onEnter:function(){1==this.filteredItems.length&&this.select(this.filteredItems[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#contentpicker").modal("hide")}}}),$(document).ready(function(){$("#contentpicker").on("shown.bs.modal",function(){$("#contentpickerSearch").trigger("focus")})}),piranha.mediapicker=new Vue({el:"#mediapicker",data:{search:"",folderName:"",listView:!0,currentFolderId:null,parentFolderId:null,currentDocumentFolderId:null,parentDocumentFolderId:null,currentImageFolderId:null,parentImageFolderId:null,currentVideoFolderId:null,parentVideoFolderId:null,currentFolderBreadcrumb:null,folders:[],items:[],folder:{name:null},filter:null,callback:null,dropzone:null},computed:{filteredFolders:function(){return this.folders.filter(function(e){return!(piranha.mediapicker.search.length>0)||e.name.toLowerCase().indexOf(piranha.mediapicker.search.toLowerCase())>-1})},filteredItems:function(){return this.items.filter(function(e){return!(piranha.mediapicker.search.length>0)||e.filename.toLowerCase().indexOf(piranha.mediapicker.search.toLowerCase())>-1})}},methods:{toggle:function(){this.listView=!this.listView},load:function(e){var t=this,i=piranha.baseUrl+"manager/api/media/list"+(e?"/"+e:"")+"/?width=210&height=160";t.filter&&(i+="&filter="+t.filter),fetch(i).then(function(e){return e.json()}).then(function(e){if(t.currentFolderId=e.currentFolderId,t.parentFolderId=e.parentFolderId,t.folders=e.folders,t.items=e.media,t.listView="list"===e.viewMode,t.search="",t.currentFolderBreadcrumb=e.currentFolderBreadcrumb,t.filter)switch(t.filter.toLowerCase()){case"document":t.currentDocumentFolderId=e.currentFolderId,t.parentDocumentFolderId=e.parentFolderId;break;case"image":t.currentImageFolderId=e.currentFolderId,t.parentImageFolderId=e.parentFolderId;break;case"video":t.currentVideoFolderId=e.currentFolderId,t.parentVideoFolderId=e.parentFolderId}}).catch(function(e){console.log("error:",e)})},getThumbnailUrl:function(e){return null!==e.altVersionUrl?e.altVersionUrl:piranha.baseUrl+"manager/api/media/url/"+e.id+"/210/160"},refresh:function(){piranha.mediapicker.load(piranha.mediapicker.currentFolderId)},open:function(e,t,i){this.search="",this.callback=e,this.filter=t,this.load(i),$("#mediapicker").modal("show")},openCurrentFolder:function(e,t){this.callback=e,this.filter=t;var i=this.currentFolderId;if(t)switch(t.toLowerCase()){case"document":i=this.currentDocumentFolderId?this.currentDocumentFolderId:i;break;case"image":i=this.currentImageFolderId?this.currentImageFolderId:i;break;case"video":i=this.currentVideoFolderId?this.currentVideoFolderId:i}this.load(i),$("#mediapicker").modal("show")},onEnter:function(){0===this.filteredItems.length&&1===this.filteredFolders.length&&(this.load(this.filteredFolders[0].id),this.search=""),1===this.filteredItems.length&&0===this.filteredFolders.length&&this.select(this.filteredItems[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#mediapicker").modal("hide")},savefolder:function(){var e=this;""!==e.folderName&&fetch(piranha.baseUrl+"manager/api/media/folder/save"+(e.filter?"?filter="+e.filter:""),{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({parentId:e.currentFolderId,name:e.folderName})}).then(function(e){return e.json()}).then(function(t){"success"===t.status.type&&(e.folderName=null,e.folders=t.folders,e.items=t.media),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})}},mounted:function(){var e=this;piranha.permissions.load(function(){piranha.permissions.media.add&&(e.dropzone=piranha.dropzone.init("#mediapicker-upload-container"),e.dropzone.on("complete",function(t){"success"===t.status&&setTimeout(function(){e.dropzone.removeFile(t)},3e3)}),e.dropzone.on("queuecomplete",function(){piranha.mediapicker.refresh()}))})}}),$(document).ready(function(){$("#mediapicker").on("shown.bs.modal",function(){$("#mediapickerSearch").trigger("focus")})}),piranha.pagepicker=new Vue({el:"#pagepicker",data:{search:"",sites:[],items:[],currentSiteId:null,currentSiteTitle:null,filter:null,callback:null},computed:{filteredItems:function(){var e=this;return this.items.filter(function(t){return!(e.search.length>0)||t.title.toLowerCase().indexOf(e.search.toLowerCase())>-1})}},methods:{load:function(e){var t=piranha.baseUrl+"manager/api/page/sitemap"+(e?"/"+e:""),i=this;fetch(t).then(function(e){return e.json()}).then(function(e){i.currentSiteId=e.siteId,i.currentSiteTitle=e.siteTitle,i.sites=e.sites,i.items=e.items}).catch(function(e){console.log("error:",e)})},refresh:function(){this.load(piranha.pagepicker.currentSiteId)},open:function(e,t){this.search="",this.callback=e,this.load(t),$("#pagepicker").modal("show")},onEnter:function(){1==this.filteredItems.length&&this.select(this.filteredItems[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#pagepicker").modal("hide")}}}),$(document).ready(function(){$("#pagepicker").on("shown.bs.modal",function(){$("#pagepickerSearch").trigger("focus")})}),piranha.postpicker=new Vue({el:"#postpicker",data:{search:"",sites:[],archives:[],posts:[],currentSiteId:null,currentArchiveId:null,currentSiteTitle:null,currentArchiveTitle:null,filter:null,callback:null},computed:{filteredPosts:function(){return this.posts.filter(function(e){return!(piranha.postpicker.search.length>0)||e.title.toLowerCase().indexOf(piranha.postpicker.search.toLowerCase())>-1})}},methods:{load:function(e,t){var i=piranha.baseUrl+"manager/api/post/modal";e&&(i+="?siteId="+e,t&&(i+="&archiveId="+t)),fetch(i).then(function(e){return e.json()}).then(function(e){piranha.postpicker.sites=e.sites,piranha.postpicker.archives=e.archives,piranha.postpicker.posts=e.posts,piranha.postpicker.currentSiteId=e.siteId,piranha.postpicker.currentArchiveId=e.archiveId,piranha.postpicker.currentSiteTitle=e.siteTitle,piranha.postpicker.currentArchiveTitle=e.archiveTitle}).catch(function(e){console.log("error:",e)})},refresh:function(){this.load(this.currentSiteId,this.currentArchiveId)},open:function(e,t,i,n){this.search="",this.callback=e,this.load(t,i),$("#postpicker").modal("show")},onEnter:function(){1==this.filteredPosts.length&&this.select(this.filteredPosts[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#postpicker").modal("hide")}}}),$(document).ready(function(){$("#postpicker").on("shown.bs.modal",function(){$("#postpickerSearch").trigger("focus")})}),piranha.preview=new Vue({el:"#previewModal",data:{empty:{filename:null,type:null,contentType:null,publicUrl:null,size:null,width:null,height:null,title:null,altText:null,description:null,lastModified:null},media:null,dropzone:null},methods:{openItem:function(e){piranha.preview.media=e,piranha.preview.show()},open:function(e){piranha.preview.load(e),piranha.preview.show()},load:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/media/"+e).then(function(e){return e.json()}).then(function(e){t.media=e}).catch(function(e){console.log("error:",e)})},saveMeta:function(e){var t=this,i={id:e.id,title:e.title,altText:e.altText,description:e.description,properties:e.properties};fetch(piranha.baseUrl+"manager/api/media/meta/save",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),"success"===e.type&&t.close()}).catch(function(e){console.log("error:",e)})},show:function(){$("#previewModal").modal("show")},close:function(){$("#previewModal").modal("hide"),setTimeout(function(){piranha.preview.clear()},300)},clear:function(){this.media=this.empty}},created:function(){this.clear()},mounted:function(){this.dropzone=piranha.dropzone.init("#media-update-container",{uploadMultiple:!1}),this.dropzone.on("complete",function(e){setTimeout(function(){piranha.preview.dropzone.removeFile(e)},3e3)}),this.dropzone.on("queuecomplete",function(){piranha.preview.load(piranha.preview.media.id),piranha.media.refresh()})}}),piranha.languageedit=new Vue({el:"#languageedit",data:{loading:!0,items:[],originalDefault:null,currentDefault:null,showDefaultInfo:!1,currentDelete:null,showDeleteInfo:!1},methods:{bind:function(e){for(var t=0;t<e.items.length;t++)e.items[t].errorTitle=!1,e.items[t].isDefault&&(this.originalDefault=this.currentDefault=e.items[t]);this.items=e.items,this.showDefaultInfo=!1,this.showDeleteInfo=!1,this.currentDelete=null,this.loading=!1},load:function(){var e=this;e.loading=!0,fetch(piranha.baseUrl+"manager/api/language").then(function(e){return e.json()}).then(function(t){e.bind(t)}).catch(function(t){console.log("error:",t),e.loading=!1})},save:function(){if(this.validate()){var e=this;e.loading=!0,fetch(piranha.baseUrl+"manager/api/language",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:JSON.parse(JSON.stringify(e.items))})}).then(function(e){return e.json()}).then(function(t){e.bind(t)}).catch(function(e){console.log("error:",e)})}},remove:function(e){var t=this;t.loading=!0,fetch(piranha.baseUrl+"manager/api/language/"+e.id,{method:"delete",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},open:function(){this.load(),$("#languageedit").modal("show")},close:function(){$("#languageedit").modal("hide")},addItem:function(){this.items.push({id:"00000000-0000-0000-0000-000000000000",title:"",culture:"",isDefault:!1})},setDefault:function(e){if(!e.isDefault){for(var t=0;t<this.items.length;t++)this.items[t].id!=e.id&&(this.items[t].isDefault=!1);e.isDefault=!0,this.currentDefault=e,this.originalDefault!=e&&(this.showDefaultInfo=!0)}},setDefaultConfirm:function(e){this.showDefaultInfo=!1},setDefaultCancel:function(e){this.setDefault(this.originalDefault),this.currentDefault=this.originalDefault,this.showDefaultInfo=!1},removeItem:function(e){this.currentDelete=e,this.showDeleteInfo=!0},removeConfirm:function(){this.remove(this.currentDelete)},removeCancel:function(){this.currentDelete=null,this.showDeleteInfo=!1},validate:function(e){isValid=!0;for(var t=0;t<this.items.length;t++)null===this.items[t].title||""===this.items[t].title?(this.items[t].errorTitle=!0,isValid=!1):this.items[t].errorTitle=!1,Vue.set(this.items,t,this.items[t]);return isValid}}}),piranha.resources=new function(){"use strict";var e=this;this.texts={},this.init=function(t){e.texts=t}},piranha.editor={editors:[],addInline:function(e,t){console.log("No HTML editor registered.")},addInlineMarkdown:function(e,t,i){var n=$("#"+e).parent().find(".markdown-preview"),r=new SimpleMDE({element:document.getElementById(e),status:!1,spellChecker:!0,hideIcons:["preview","guide"],initialValue:t,toolbar:["bold","italic","heading","|","quote","unordered-list","ordered-list","|","link",{name:"image",action:function(e){piranha.mediapicker.openCurrentFolder(function(t){var i=e.codemirror,n=r.getState(i).image,o=i.getCursor("start"),a=i.getCursor("end");n?(text=i.getLine(o.line),i.replaceRange("",{line:o.line,ch:0})):i.replaceSelection(""),i.setSelection(o,a),i.focus()},"Image")},className:"fa fa-picture-o",title:"Image"},"side-by-side","fullscreen"],renderingConfig:{singleLineBreaks:!1}});r.codemirror.on("change",function(){n.html(r.markdown(r.value())),i(r.value())}),setTimeout(function(){n.html(r.markdown(r.value())),r.codemirror.refresh()}.bind(r),0),this.editors[e]=r},remove:function(e){console.log("No HTML editor registered.")},removeMarkdown:function(e){var t=this.editors[e];if(null!=t){this.editors.indexOf(t);t.toTextArea(),this.editors.splice[1]}},refreshMarkdown:function(){for(var e in this.editors)this.editors.hasOwnProperty(e)&&this.editors[e].codemirror.refresh()}},$(document).on("focusin",function(e){$(e.target).closest(".tox-tinymce-inline").length&&e.stopImmediatePropagation()}),Vue.component("page-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li :data-id="item.id" class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }">\n <div class="sitemap-item expanded">\n <div class="link">\n <span class="actions">\n <a v-if="item.items.length > 0 && item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-minus"></i></a>\n <a v-if="item.items.length > 0 && !item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-plus"></i></a>\n </span>\n <a href="#" v-on:click.prevent="piranha.pagepicker.select(item)">\n {{ item.title }}\n </a>\n </div>\n <div class="type d-none d-md-block">\n {{ item.typeName }}\n </div>\n </div>\n <ol class="dd-list" v-if="item.items.length > 0">\n <page-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child">\n </page-item>\n </ol>\n</li>\n'}); \ No newline at end of file +Vue.prototype.eventBus=new Vue,piranha.accessibility=new function(){"use strict";var e=this;e.focus=null,e.removeBlock=function(e){var t=$(":focus").parents(".block");if(1===t.length){if(tinymce){var i=tinymce.activeEditor;i&&i.inline&&i.destroy()}t.find(".block-remove").click()}},$(document).on("show.bs.modal",".modal",function(){e.focus=$(":focus")}),$(document).on("hidden.bs.modal",".modal",function(){e.focus&&(e.focus.focus(),e.focus=null)}),$(window).on("keydown",function(t){$(".main-nav");t.altKey&&(67===t.keyCode?$("#contentSelector").click():8===t.keyCode&&e.removeBlock(t))})},piranha.alert=new Vue({el:"#alert",data:{title:null,body:null,confirmCss:null,confirmIcon:null,confirmText:null,cancelCss:null,cancelIcon:null,cancelText:null,onConfirm:null,onCancel:null,verifyPhrase:null,verifyPlaceholder:null,verifyText:null,verifyInput:null},methods:{open:function(e){e&&(this.title=e.title,this.body=e.body,this.confirmCss=e.confirmCss?e.confirmCss:"btn-success",this.confirmIcon=e.confirmIcon,this.confirmText=e.confirmText?e.confirmText:piranha.resources.texts.ok,this.cancelCss=e.cancelCss?e.cancelCss:"btn-secondary",this.cancelIcon=e.cancelIcon,this.cancelText=e.cancelText?e.cancelText:piranha.resources.texts.cancel,this.onConfirm=e.onConfirm,this.onCancel=e.onCancel,this.verifyPhrase=e.verifyPhrase,this.verifyPlaceholder=e.verifyPlaceholder,this.verifyText=e.verifyText,$("#alert").modal("show"))},confirm:function(){this.onConfirm&&(this.onConfirm(),this.clear()),$("#alert").modal("hide")},cancel:function(){this.onCancel&&(this.onCancel(),this.clear()),$("#alert").modal("hide")},canConfirm:function(){return!this.verifyPhrase||this.verifyPhrase===this.verifyInput},clear:function(){this.onCancel=null,this.onConfirm=null,this.verifyInput=null}}}),Dropzone.autoDiscover=!1,piranha.dropzone=new function(){this.init=function(e,t){t||(t={});var i={paramName:"Uploads",url:piranha.baseUrl+"manager/api/media/upload",headers:piranha.utils.antiForgeryHeaders(!1),thumbnailWidth:70,thumbnailHeight:70,previewsContainer:e+" .media-list",previewTemplate:document.querySelector("#media-upload-template").innerHTML,uploadMultiple:!0,init:function(){t.addedfile||(t.addedfile=function(e){}),t.removedfile||(t.removedfile=function(e){}),t.error||(t.error=function(e){}),t.complete||(t.complete=function(e){if("success"!==e.status&&""!==e.xhr.responseText){var t=JSON.parse(e.xhr.responseText);e.previewElement.querySelector("[data-dz-errormessage]").innerText=t.body}}),t.queuecomplete||(t.queuecomplete=function(){}),this.on("addedfile",t.addedfile),this.on("removedfile",t.removedfile),this.on("complete",t.complete),this.on("queuecomplete",t.queuecomplete)}},n=Object.assign(i,t);return new Dropzone(e+" form",n)}},piranha.permissions={loaded:!1,aliases:{edit:!1,delete:!1},comments:{approve:!1,delete:!1},media:{add:!1,addFolder:!1,delete:!1,deleteFolder:!1,edit:!1},pages:{add:!1,delete:!1,edit:!1,preview:!1,publish:!1,save:!1},posts:{add:!1,delete:!1,edit:!1,preview:!1,publish:!1,save:!1},sites:{add:!1,delete:!1,edit:!1,save:!1},load:function(e){var t=this;this.loaded?e&&e():fetch(piranha.baseUrl+"manager/api/permissions").then(function(e){return e.json()}).then(function(i){t.aliases=i.aliases,t.comments=i.comments,t.media=i.media,t.pages=i.pages,t.posts=i.posts,t.sites=i.sites,t.loaded=!0,e&&e()}).catch(function(t){console.log("error:",t),e&&e()})}},piranha.utils={formatUrl:function(e){return e.replace("~/",piranha.baseUrl)},isEmptyHtml:function(e){return null==e||""==e.replace(/(<([^>]+)>)/gi,"").replace(/\s/g,"")&&-1===e.indexOf("<img")},isEmptyText:function(e){return null==e||""==e.replace(/\s/g,"")||"<br>"==e.replace(/\s/g,"")},strLength:function(e){return null!=e?e.length:0},antiForgery:function(){const e=document.cookie.split(";");for(let t=0;t<e.length;t++){let i=e[t].trim().split("=");if(i[0]===piranha.antiForgery.cookieName)return i[1]}return""},antiForgeryHeaders:function(e){var t={};return void 0!==e&&!0!==e||(t["Content-Type"]="application/json"),t[piranha.antiForgery.headerName]=piranha.utils.antiForgery(),t}},Date.prototype.addDays=function(e){var t=new Date(this.valueOf());return t.setDate(t.getDate()+e),t},Date.prototype.toDateString=function(e){var t=new Date(this.valueOf());return t.getFullYear()+"-"+String(t.getMonth()+1).padStart(2,"0")+"-"+String(t.getDate()).padStart(2,"0")},$(document).ready(function(){$(".block-header .danger").hover(function(){$(this).closest(".block").addClass("danger")},function(){$(this).closest(".block").removeClass("danger")}),$("form.validate").submit(function(e){!1===$(this).get(0).checkValidity()&&(e.preventDefault(),e.stopPropagation(),$(this).addClass("was-validated"))})}),$(document).on("mouseenter",".block-header .danger",function(){$(this).closest(".block").addClass("danger")}),$(document).on("mouseleave",".block-header .danger",function(){$(this).closest(".block").removeClass("danger")}),$(document).on("shown.bs.collapse",".collapse",function(){$(this).parent().addClass("active")}),$(document).on("hide.bs.collapse",".collapse",function(){$(this).parent().removeClass("active")}),$(document).on("hidden.bs.modal",".modal",function(){$(".modal:visible").length&&$(document.body).addClass("modal-open")}),$(window).scroll(function(){var e=$(this).scrollTop();$(".app .component-toolbar").each(function(){var t=$(this).parent(),i=t.offset().top;if(e>i){var n=t.outerHeight();e>i+n?$(this).css({top:n+"px"}):$(this).css({top:e-i+"px"})}else $(this).removeAttr("style")})}),piranha.blockpicker=new Vue({el:"#blockpicker",data:{filter:"",categories:[],index:0,callback:null},computed:{filteredCategories:function(){var e=this;return this.categories.filter(function(t){return e.filterBlockTypes(t).length>0})}},methods:{open:function(e,t,i){var n=this,r=piranha.baseUrl+"manager/api/content/blocktypes";piranha.pageedit?r+="/page/"+piranha.pageedit.typeId:piranha.postedit&&(r+="/post/"+piranha.postedit.typeId),fetch(r+(null!=i?"/"+i:"")).then(function(e){return e.json()}).then(function(i){i.typeCount>1?(n.filter="",n.index=t,n.callback=e,n.categories=i.categories,$("#blockpicker").modal("show")):e(i.categories[0].items[0].type,t)}).catch(function(e){console.log("error:",e)})},select:function(e){this.callback(e.type,this.index),this.index=0,this.callback=null,$("#blockpicker").modal("hide")},selectSingleItem:function(){var e=this.filteredCategories;if(1===e.length){var t=this.filterBlockTypes(e[0]);1===t.length&&this.select(t[0])}},filterBlockTypes:function(e){var t=this;return e.items.filter(function(e){return e.name.toLowerCase().indexOf(t.filter.toLowerCase())>-1})}},created:function(){}}),$(document).ready(function(){$("#blockpicker").on("shown.bs.modal",function(){$("#blockpickerSearch").trigger("focus")})}),piranha.notifications=new Vue({el:"#notification-hub",data:{items:[]},methods:{unauthorized:function(){this.push({type:"danger",body:"Request sender could not be verified by the server.",hide:!0})},push:function(e){e.style={visible:!1,"notification-info":"info"===e.type,"notification-danger":"danger"===e.type,"notification-success":"success"===e.type,"notification-warning":"warning"===e.type},piranha.notifications.items.push(e),setTimeout(function(){e.style.visible=!0,e.hide&&setTimeout(function(){e.style.visible=!1,setTimeout(function(){piranha.notifications.items.shift()},200)},5e3)},200)}}}),piranha.contentpicker=new Vue({el:"#contentpicker",data:{search:"",groups:[],items:[],currentGroupId:null,currentGroupTitle:null,currentGroupIcon:null,filter:null,callback:null},computed:{filteredItems:function(){var e=this;return this.items.filter(function(t){return!(e.search.length>0)||t.title.toLowerCase().indexOf(e.search.toLowerCase())>-1})}},methods:{bind:function(e,t){this.currentGroupId=e.group.id,this.currentGroupTitle=e.group.title,this.currentGroupIcon=e.group.icon,this.types=e.types,this.items=e.items.map(function(t){var i=e.types.find(function(e){return e.id===t.typeId});return t.type=i.title||t.typeId,t}),t||(this.groups=e.groups)},load:function(e,t){var i=piranha.baseUrl+"manager/api/content/"+(e?e+"/":"")+"list",n=this;fetch(i).then(function(e){return e.json()}).then(function(e){n.bind(e,t)}).catch(function(e){console.log("error:",e)})},loadGroups:function(){},refresh:function(){this.load(piranha.contentpicker.currentGroupId,!0)},open:function(e,t){this.search="",this.callback=t,this.load(e),$("#contentpicker").modal("show")},onEnter:function(){1==this.filteredItems.length&&this.select(this.filteredItems[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#contentpicker").modal("hide")}}}),$(document).ready(function(){$("#contentpicker").on("shown.bs.modal",function(){$("#contentpickerSearch").trigger("focus")})}),piranha.mediapicker=new Vue({el:"#mediapicker",data:{search:"",folderName:"",listView:!0,currentFolderId:null,parentFolderId:null,currentDocumentFolderId:null,parentDocumentFolderId:null,currentImageFolderId:null,parentImageFolderId:null,currentVideoFolderId:null,parentVideoFolderId:null,currentFolderBreadcrumb:null,folders:[],items:[],folder:{name:null},filter:null,callback:null,dropzone:null},computed:{filteredFolders:function(){return this.folders.filter(function(e){return!(piranha.mediapicker.search.length>0)||e.name.toLowerCase().indexOf(piranha.mediapicker.search.toLowerCase())>-1})},filteredItems:function(){return this.items.filter(function(e){return!(piranha.mediapicker.search.length>0)||e.filename.toLowerCase().indexOf(piranha.mediapicker.search.toLowerCase())>-1})}},methods:{toggle:function(){this.listView=!this.listView},load:function(e){var t=this,i=piranha.baseUrl+"manager/api/media/list"+(e?"/"+e:"")+"/?width=210&height=160";t.filter&&(i+="&filter="+t.filter),fetch(i).then(function(e){return e.json()}).then(function(e){if(t.currentFolderId=e.currentFolderId,t.parentFolderId=e.parentFolderId,t.folders=e.folders,t.items=e.media,t.listView="list"===e.viewMode,t.search="",t.currentFolderBreadcrumb=e.currentFolderBreadcrumb,t.filter)switch(t.filter.toLowerCase()){case"document":t.currentDocumentFolderId=e.currentFolderId,t.parentDocumentFolderId=e.parentFolderId;break;case"image":t.currentImageFolderId=e.currentFolderId,t.parentImageFolderId=e.parentFolderId;break;case"video":t.currentVideoFolderId=e.currentFolderId,t.parentVideoFolderId=e.parentFolderId}}).catch(function(e){console.log("error:",e)})},getThumbnailUrl:function(e){return null!==e.altVersionUrl?e.altVersionUrl:piranha.baseUrl+"manager/api/media/url/"+e.id+"/210/160"},refresh:function(){piranha.mediapicker.load(piranha.mediapicker.currentFolderId)},open:function(e,t,i){this.search="",this.callback=e,this.filter=t,this.load(i),$("#mediapicker").modal("show")},openCurrentFolder:function(e,t){this.callback=e,this.filter=t;var i=this.currentFolderId;if(t)switch(t.toLowerCase()){case"document":i=this.currentDocumentFolderId?this.currentDocumentFolderId:i;break;case"image":i=this.currentImageFolderId?this.currentImageFolderId:i;break;case"video":i=this.currentVideoFolderId?this.currentVideoFolderId:i}this.load(i),$("#mediapicker").modal("show")},onEnter:function(){0===this.filteredItems.length&&1===this.filteredFolders.length&&(this.load(this.filteredFolders[0].id),this.search=""),1===this.filteredItems.length&&0===this.filteredFolders.length&&this.select(this.filteredItems[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#mediapicker").modal("hide")},savefolder:function(){var e=this;""!==e.folderName&&fetch(piranha.baseUrl+"manager/api/media/folder/save"+(e.filter?"?filter="+e.filter:""),{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({parentId:e.currentFolderId,name:e.folderName})}).then(function(e){return e.json()}).then(function(t){"success"===t.status.type&&(e.folderName=null,e.folders=t.folders,e.items=t.media),400!==t.status?piranha.notifications.push(t.status):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})}},mounted:function(){var e=this;piranha.permissions.load(function(){piranha.permissions.media.add&&(e.dropzone=piranha.dropzone.init("#mediapicker-upload-container"),e.dropzone.on("complete",function(t){"success"===t.status&&setTimeout(function(){e.dropzone.removeFile(t)},3e3)}),e.dropzone.on("queuecomplete",function(){piranha.mediapicker.refresh()}))})}}),$(document).ready(function(){$("#mediapicker").on("shown.bs.modal",function(){$("#mediapickerSearch").trigger("focus")})}),piranha.pagepicker=new Vue({el:"#pagepicker",data:{search:"",sites:[],items:[],currentSiteId:null,currentSiteTitle:null,filter:null,callback:null},computed:{filteredItems:function(){var e=this;return this.items.filter(function(t){return!(e.search.length>0)||t.title.toLowerCase().indexOf(e.search.toLowerCase())>-1})}},methods:{load:function(e){var t=piranha.baseUrl+"manager/api/page/sitemap"+(e?"/"+e:""),i=this;fetch(t).then(function(e){return e.json()}).then(function(e){i.currentSiteId=e.siteId,i.currentSiteTitle=e.siteTitle,i.sites=e.sites,i.items=e.items}).catch(function(e){console.log("error:",e)})},refresh:function(){this.load(piranha.pagepicker.currentSiteId)},open:function(e,t){this.search="",this.callback=e,this.load(t),$("#pagepicker").modal("show")},onEnter:function(){1==this.filteredItems.length&&this.select(this.filteredItems[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#pagepicker").modal("hide")}}}),$(document).ready(function(){$("#pagepicker").on("shown.bs.modal",function(){$("#pagepickerSearch").trigger("focus")})}),piranha.postpicker=new Vue({el:"#postpicker",data:{search:"",sites:[],archives:[],posts:[],currentSiteId:null,currentArchiveId:null,currentSiteTitle:null,currentArchiveTitle:null,filter:null,callback:null},computed:{filteredPosts:function(){return this.posts.filter(function(e){return!(piranha.postpicker.search.length>0)||e.title.toLowerCase().indexOf(piranha.postpicker.search.toLowerCase())>-1})}},methods:{load:function(e,t){var i=piranha.baseUrl+"manager/api/post/modal";e&&(i+="?siteId="+e,t&&(i+="&archiveId="+t)),fetch(i).then(function(e){return e.json()}).then(function(e){piranha.postpicker.sites=e.sites,piranha.postpicker.archives=e.archives,piranha.postpicker.posts=e.posts,piranha.postpicker.currentSiteId=e.siteId,piranha.postpicker.currentArchiveId=e.archiveId,piranha.postpicker.currentSiteTitle=e.siteTitle,piranha.postpicker.currentArchiveTitle=e.archiveTitle}).catch(function(e){console.log("error:",e)})},refresh:function(){this.load(this.currentSiteId,this.currentArchiveId)},open:function(e,t,i,n){this.search="",this.callback=e,this.load(t,i),$("#postpicker").modal("show")},onEnter:function(){1==this.filteredPosts.length&&this.select(this.filteredPosts[0])},select:function(e){this.callback(JSON.parse(JSON.stringify(e))),this.callback=null,this.search="",$("#postpicker").modal("hide")}}}),$(document).ready(function(){$("#postpicker").on("shown.bs.modal",function(){$("#postpickerSearch").trigger("focus")})}),piranha.preview=new Vue({el:"#previewModal",data:{empty:{filename:null,type:null,contentType:null,publicUrl:null,size:null,width:null,height:null,title:null,altText:null,description:null,lastModified:null},media:null,dropzone:null},methods:{openItem:function(e){piranha.preview.media=e,piranha.preview.show()},open:function(e){piranha.preview.load(e),piranha.preview.show()},load:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/media/"+e).then(function(e){return e.json()}).then(function(e){t.media=e}).catch(function(e){console.log("error:",e)})},saveMeta:function(e){var t=this,i={id:e.id,title:e.title,altText:e.altText,description:e.description,properties:e.properties};fetch(piranha.baseUrl+"manager/api/media/meta/save",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),"success"===e.type&&t.close()}).catch(function(e){console.log("error:",e)})},show:function(){$("#previewModal").modal("show")},close:function(){$("#previewModal").modal("hide"),setTimeout(function(){piranha.preview.clear()},300)},clear:function(){this.media=this.empty}},created:function(){this.clear()},mounted:function(){this.dropzone=piranha.dropzone.init("#media-update-container",{uploadMultiple:!1}),this.dropzone.on("complete",function(e){setTimeout(function(){piranha.preview.dropzone.removeFile(e)},3e3)}),this.dropzone.on("queuecomplete",function(){piranha.preview.load(piranha.preview.media.id),piranha.media.refresh()})}}),piranha.languageedit=new Vue({el:"#languageedit",data:{loading:!0,items:[],originalDefault:null,currentDefault:null,showDefaultInfo:!1,currentDelete:null,showDeleteInfo:!1},methods:{bind:function(e){for(var t=0;t<e.items.length;t++)e.items[t].errorTitle=!1,e.items[t].isDefault&&(this.originalDefault=this.currentDefault=e.items[t]);this.items=e.items,this.showDefaultInfo=!1,this.showDeleteInfo=!1,this.currentDelete=null,this.loading=!1},load:function(){var e=this;e.loading=!0,fetch(piranha.baseUrl+"manager/api/language").then(function(e){return e.json()}).then(function(t){e.bind(t)}).catch(function(t){console.log("error:",t),e.loading=!1})},save:function(){if(this.validate()){var e=this;e.loading=!0,fetch(piranha.baseUrl+"manager/api/language",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({items:JSON.parse(JSON.stringify(e.items))})}).then(function(e){return e.json()}).then(function(t){"success"===t.status.type&&e.bind(t),400!==t.status?piranha.notifications.push(t.status):(piranha.notifications.unauthorized(),e.loading=!1)}).catch(function(e){console.log("error:",e)})}},remove:function(e){var t=this;t.loading=!0,fetch(piranha.baseUrl+"manager/api/language/"+e.id,{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e)}).then(function(e){return e.json()}).then(function(e){"success"===e.status.type&&t.bind(e),400!==e.status?piranha.notifications.push(e.status):(piranha.notifications.unauthorized(),t.loading=!1)}).catch(function(e){console.log("error:",e)})},open:function(){this.load(),$("#languageedit").modal("show")},close:function(){$("#languageedit").modal("hide")},addItem:function(){this.items.push({id:"00000000-0000-0000-0000-000000000000",title:"",culture:"",isDefault:!1})},setDefault:function(e){if(!e.isDefault){for(var t=0;t<this.items.length;t++)this.items[t].id!=e.id&&(this.items[t].isDefault=!1);e.isDefault=!0,this.currentDefault=e,this.originalDefault!=e&&(this.showDefaultInfo=!0)}},setDefaultConfirm:function(e){this.showDefaultInfo=!1},setDefaultCancel:function(e){this.setDefault(this.originalDefault),this.currentDefault=this.originalDefault,this.showDefaultInfo=!1},removeItem:function(e){this.currentDelete=e,this.showDeleteInfo=!0},removeConfirm:function(){this.remove(this.currentDelete)},removeCancel:function(){this.currentDelete=null,this.showDeleteInfo=!1},validate:function(e){isValid=!0;for(var t=0;t<this.items.length;t++)null===this.items[t].title||""===this.items[t].title?(this.items[t].errorTitle=!0,isValid=!1):this.items[t].errorTitle=!1,Vue.set(this.items,t,this.items[t]);return isValid}}}),piranha.resources=new function(){"use strict";var e=this;this.texts={},this.init=function(t){e.texts=t}},piranha.editor={editors:[],addInline:function(e,t){console.log("No HTML editor registered.")},addInlineMarkdown:function(e,t,i){var n=$("#"+e).parent().find(".markdown-preview"),r=new SimpleMDE({element:document.getElementById(e),status:!1,spellChecker:!0,hideIcons:["preview","guide"],initialValue:t,toolbar:["bold","italic","heading","|","quote","unordered-list","ordered-list","|","link",{name:"image",action:function(e){piranha.mediapicker.openCurrentFolder(function(t){var i=e.codemirror,n=r.getState(i).image,o=i.getCursor("start"),a=i.getCursor("end");n?(text=i.getLine(o.line),i.replaceRange("",{line:o.line,ch:0})):i.replaceSelection(""),i.setSelection(o,a),i.focus()},"Image")},className:"fa fa-picture-o",title:"Image"},"side-by-side","fullscreen"],renderingConfig:{singleLineBreaks:!1}});r.codemirror.on("change",function(){n.html(r.markdown(r.value())),i(r.value())}),setTimeout(function(){n.html(r.markdown(r.value())),r.codemirror.refresh()}.bind(r),0),this.editors[e]=r},remove:function(e){console.log("No HTML editor registered.")},removeMarkdown:function(e){var t=this.editors[e];if(null!=t){this.editors.indexOf(t);t.toTextArea(),this.editors.splice[1]}},refreshMarkdown:function(){for(var e in this.editors)this.editors.hasOwnProperty(e)&&this.editors[e].codemirror.refresh()}},$(document).on("focusin",function(e){$(e.target).closest(".tox-tinymce-inline").length&&e.stopImmediatePropagation()}),Vue.component("page-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li :data-id="item.id" class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }">\n <div class="sitemap-item expanded">\n <div class="link">\n <span class="actions">\n <a v-if="item.items.length > 0 && item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-minus"></i></a>\n <a v-if="item.items.length > 0 && !item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-plus"></i></a>\n </span>\n <a href="#" v-on:click.prevent="piranha.pagepicker.select(item)">\n {{ item.title }}\n </a>\n </div>\n <div class="type d-none d-md-block">\n {{ item.typeName }}\n </div>\n </div>\n <ol class="dd-list" v-if="item.items.length > 0">\n <page-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child">\n </page-item>\n </ol>\n</li>\n'}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.pageedit.js+30 −19 modified@@ -280,9 +280,7 @@ piranha.pageedit = new Vue({ fetch(route, { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -314,29 +312,38 @@ piranha.pageedit = new Vue({ revert: function () { var self = this; - fetch(piranha.baseUrl + "manager/api/page/revert/" + self.id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/page/revert", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); + piranha.notifications.push(result.status); + }) + .catch(function (error) { + console.log("error:", error ); }); }, detach: function () { var self = this; - fetch(piranha.baseUrl + "manager/api/page/detach/" + self.id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/page/detach", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); + piranha.notifications.push(result.status); + }) + .catch(function (error) { + console.log("error:", error ); }); - }, remove: function () { var self = this; @@ -348,7 +355,11 @@ piranha.pageedit = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/page/delete/" + self.id) + fetch(piranha.baseUrl + "manager/api/page/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/dist/js/piranha.pageedit.min.js+1 −1 modified@@ -1 +1 @@ -piranha.pageedit=new Vue({el:"#pageedit",data:{loading:!0,id:null,siteId:null,parentId:null,originalId:null,sortOrder:0,typeId:null,title:null,navigationTitle:null,slug:null,metaTitle:null,metaKeywords:null,metaDescription:null,metaIndex:null,metaFollow:null,metaPriority:null,ogTitle:null,ogDescription:null,ogImage:{id:null,media:null},excerpt:null,isHidden:!1,published:null,publishedTime:null,redirectUrl:null,redirectType:null,enableComments:null,closeCommentsAfterDays:null,commentCount:null,pendingCommentCount:0,state:"new",blocks:[],regions:[],editors:[],useBlocks:!0,usePrimaryImage:!0,useExcerpt:!0,useHtmlExcerpt:!0,permissions:[],primaryImage:{id:null,media:null},selectedPermissions:[],isCopy:!1,isScheduled:!1,saving:!1,savingDraft:!1,selectedRegion:{uid:"uid-blocks",name:null,icon:null},selectedSetting:"uid-settings",selectedRoute:null,routes:[]},computed:{contentRegions:function(){return this.regions.filter(function(e){return"setting"!=e.meta.display&&"hidden"!=e.meta.display})},settingRegions:function(){return this.regions.filter(function(e){return"setting"===e.meta.display})},primaryImageUrl:function(){return null!=this.primaryImage.media?piranha.utils.formatUrl("~/manager/api/media/url/"+this.primaryImage.id+"/448/200"):piranha.utils.formatUrl("~/manager/assets/img/empty-image.png")},isExcerptEmpty:function(){return piranha.utils.isEmptyText(this.excerpt)},metaPriorityDescription:function(){var e=piranha.resources.texts.important;return this.metaPriority<=.3?e=piranha.resources.texts.low:this.metaPriority<=.6?e=piranha.resources.texts.medium:this.metaPriority<=.9&&(e=piranha.resources.texts.high),e+" ("+this.metaPriority+")"}},mounted(){document.addEventListener("keydown",this.doHotKeys)},beforeDestroy(){document.removeEventListener("keydown",this.doHotKeys)},methods:{bind:function(e){this.id=e.id,this.siteId=e.siteId,this.parentId=e.parentId,this.originalId=e.originalId,this.sortOrder=e.sortOrder,this.typeId=e.typeId,this.title=e.title,this.navigationTitle=e.navigationTitle,this.slug=e.slug,this.metaTitle=e.metaTitle,this.metaKeywords=e.metaKeywords,this.metaDescription=e.metaDescription,this.metaIndex=e.metaIndex,this.metaFollow=e.metaFollow,this.metaPriority=e.metaPriority,this.ogTitle=e.ogTitle,this.ogDescription=e.ogDescription,this.ogImage=e.ogImage,this.excerpt=e.excerpt,this.isHidden=e.isHidden,this.published=e.published,this.publishedTime=e.publishedTime,this.redirectUrl=e.redirectUrl,this.redirectType=e.redirectType,this.enableComments=e.enableComments,this.closeCommentsAfterDays=e.closeCommentsAfterDays,this.commentCount=e.commentCount,this.pendingCommentCount=e.pendingCommentCount,this.state=e.state,this.blocks=e.blocks,this.regions=e.regions,this.editors=e.editors,this.useBlocks=e.useBlocks,this.usePrimaryImage=e.usePrimaryImage,this.useExcerpt=e.useExcerpt,this.useHtmlExcerpt=e.useHtmlExcerpt,this.isCopy=e.isCopy,this.isScheduled=e.isScheduled,this.selectedRoute=e.selectedRoute,this.routes=e.routes,this.permissions=e.permissions,this.primaryImage=e.primaryImage,this.selectedPermissions=e.selectedPermissions,this.useBlocks?this.selectedRegion={uid:"uid-blocks",name:null,icon:null}:this.editors.length>0?this.selectedRegion=this.editors[0]:this.contentRegions.length>0&&(this.selectedRegion=this.contentRegions[0].meta)},load:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/page/"+e).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},create:function(e,t){var i=this;fetch(piranha.baseUrl+"manager/api/page/create/"+e+"/"+t).then(function(e){return e.json()}).then(function(e){i.bind(e)}).catch(function(e){console.log("error:",e)})},createrelative:function(e,t,i){var n=this;fetch(piranha.baseUrl+"manager/api/page/createrelative/"+e+"/"+t+"/"+i).then(function(e){return e.json()}).then(function(e){n.bind(e)}).catch(function(e){console.log("error:",e)})},copyrelative:function(e,t,i){var n=this;fetch(piranha.baseUrl+"manager/api/page/copyrelative/"+e+"/"+t+"/"+i).then(function(e){return e.json()}).then(function(e){n.bind(e)}).catch(function(e){console.log("error:",e)})},doHotKeys(e){83===e.keyCode&&e.ctrlKey&&(e.preventDefault(),this.saveDraft())},save:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/page/save")},saveDraft:function(){this.savingDraft=!0,this.saveInternal(piranha.baseUrl+"manager/api/page/save/draft")},unpublish:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/page/save/unpublish")},saveInternal:function(e){var t=this,i={id:t.id,siteId:t.siteId,parentId:t.parentId,originalId:t.originalId,sortOrder:t.sortOrder,typeId:t.typeId,title:t.title,navigationTitle:t.navigationTitle,slug:t.slug,metaTitle:t.metaTitle,metaKeywords:t.metaKeywords,metaDescription:t.metaDescription,metaIndex:t.metaIndex,metaFollow:t.metaFollow,metaPriority:t.metaPriority,ogTitle:t.ogTitle,ogDescription:t.ogDescription,ogImage:{id:t.ogImage.id},excerpt:t.excerpt,isHidden:t.isHidden,published:t.published,publishedTime:t.publishedTime,redirectUrl:t.redirectUrl,redirectType:t.redirectType,enableComments:t.enableComments,closeCommentsAfterDays:t.closeCommentsAfterDays,isCopy:t.isCopy,blocks:JSON.parse(JSON.stringify(t.blocks)),regions:JSON.parse(JSON.stringify(t.regions)),selectedRoute:t.selectedRoute,selectedPermissions:t.selectedPermissions,primaryImage:{id:t.primaryImage.id}};fetch(e,{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){var i=t.state;t.id=e.id,t.slug=e.slug,t.published=e.published,t.publishedTime=e.publishedTime,t.state=e.state,t.isCopy=e.isCopy,t.selectedRoute=e.selectedRoute,"new"===i&&"new"!==e.state&&window.history.replaceState({state:"created"},"Edit page",piranha.baseUrl+"manager/page/edit/"+e.id),piranha.notifications.push(e.status),t.saving=!1,t.savingDraft=!1,t.eventBus.$emit("onSaved",t.state)}).catch(function(e){console.log("error:",e)})},revert:function(){var e=this;fetch(piranha.baseUrl+"manager/api/page/revert/"+e.id).then(function(e){return e.json()}).then(function(t){e.bind(t),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},detach:function(){var e=this;fetch(piranha.baseUrl+"manager/api/page/detach/"+e.id).then(function(e){return e.json()}).then(function(t){e.bind(t),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},remove:function(){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/page/delete/"+e.id).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),window.location=piranha.baseUrl+"manager/pages"}).catch(function(e){console.log("error:",e)})}})},addBlock:function(e,t){fetch(piranha.baseUrl+"manager/api/content/block/"+e).then(function(e){return e.json()}).then(function(e){piranha.pageedit.blocks.splice(t,0,e.body)}).catch(function(e){console.log("error:",e)})},moveBlock:function(e,t){this.blocks.splice(t,0,this.blocks.splice(e,1)[0])},collapseBlock:function(e){e.meta.isCollapsed=!e.meta.isCollapsed},removeBlock:function(e){var t=this.blocks.indexOf(e);-1!==t&&this.blocks.splice(t,1)},updateBlockTitle:function(e){for(var t=0;t<this.blocks.length;t++)if(this.blocks[t].meta.uid===e.uid){this.blocks[t].meta.title=e.title;break}},selectRegion:function(e){this.selectedRegion=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},selectSetting:function(e){this.selectedSetting=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},isCommentsOpen:function(){var e=new Date(this.published+" "+this.publishedTime);return(e=e.addDays(this.closeCommentsAfterDays))>new Date},commentsClosedDate:function(){var e=new Date(this.published+" "+this.publishedTime);return(e=e.addDays(this.closeCommentsAfterDays)).toDateString()},selectPrimaryImage:function(){null!==this.primaryImage.media?piranha.mediapicker.open(this.updatePrimaryImage,"Image",this.primaryImage.media.folderId):piranha.mediapicker.openCurrentFolder(this.updatePrimaryImage,"Image")},removePrimaryImage:function(){this.primaryImage.id=null,this.primaryImage.media=null},updatePrimaryImage:function(e){"Image"===e.type?(this.primaryImage.id=e.id,this.primaryImage.media=e):console.log("No image was selected")},onExcerptBlur:function(e){this.useHtmlExcerpt?this.excerpt=tinyMCE.activeEditor.getContent():this.excerpt=e.target.innerHTML}},created:function(){},updated:function(){this.loading?(sortable("#content-blocks",{handle:".handle",items:":not(.unsortable)"})[0].addEventListener("sortupdate",function(e){piranha.pageedit.moveBlock(e.detail.origin.index,e.detail.destination.index)}),piranha.editor.addInline("excerpt-body","excerpt-toolbar")):(sortable("#content-blocks","disable"),sortable("#content-blocks","enable")),this.loading=!1},components:{datepicker:vuejsDatepicker}}); \ No newline at end of file +piranha.pageedit=new Vue({el:"#pageedit",data:{loading:!0,id:null,siteId:null,parentId:null,originalId:null,sortOrder:0,typeId:null,title:null,navigationTitle:null,slug:null,metaTitle:null,metaKeywords:null,metaDescription:null,metaIndex:null,metaFollow:null,metaPriority:null,ogTitle:null,ogDescription:null,ogImage:{id:null,media:null},excerpt:null,isHidden:!1,published:null,publishedTime:null,redirectUrl:null,redirectType:null,enableComments:null,closeCommentsAfterDays:null,commentCount:null,pendingCommentCount:0,state:"new",blocks:[],regions:[],editors:[],useBlocks:!0,usePrimaryImage:!0,useExcerpt:!0,useHtmlExcerpt:!0,permissions:[],primaryImage:{id:null,media:null},selectedPermissions:[],isCopy:!1,isScheduled:!1,saving:!1,savingDraft:!1,selectedRegion:{uid:"uid-blocks",name:null,icon:null},selectedSetting:"uid-settings",selectedRoute:null,routes:[]},computed:{contentRegions:function(){return this.regions.filter(function(e){return"setting"!=e.meta.display&&"hidden"!=e.meta.display})},settingRegions:function(){return this.regions.filter(function(e){return"setting"===e.meta.display})},primaryImageUrl:function(){return null!=this.primaryImage.media?piranha.utils.formatUrl("~/manager/api/media/url/"+this.primaryImage.id+"/448/200"):piranha.utils.formatUrl("~/manager/assets/img/empty-image.png")},isExcerptEmpty:function(){return piranha.utils.isEmptyText(this.excerpt)},metaPriorityDescription:function(){var e=piranha.resources.texts.important;return this.metaPriority<=.3?e=piranha.resources.texts.low:this.metaPriority<=.6?e=piranha.resources.texts.medium:this.metaPriority<=.9&&(e=piranha.resources.texts.high),e+" ("+this.metaPriority+")"}},mounted(){document.addEventListener("keydown",this.doHotKeys)},beforeDestroy(){document.removeEventListener("keydown",this.doHotKeys)},methods:{bind:function(e){this.id=e.id,this.siteId=e.siteId,this.parentId=e.parentId,this.originalId=e.originalId,this.sortOrder=e.sortOrder,this.typeId=e.typeId,this.title=e.title,this.navigationTitle=e.navigationTitle,this.slug=e.slug,this.metaTitle=e.metaTitle,this.metaKeywords=e.metaKeywords,this.metaDescription=e.metaDescription,this.metaIndex=e.metaIndex,this.metaFollow=e.metaFollow,this.metaPriority=e.metaPriority,this.ogTitle=e.ogTitle,this.ogDescription=e.ogDescription,this.ogImage=e.ogImage,this.excerpt=e.excerpt,this.isHidden=e.isHidden,this.published=e.published,this.publishedTime=e.publishedTime,this.redirectUrl=e.redirectUrl,this.redirectType=e.redirectType,this.enableComments=e.enableComments,this.closeCommentsAfterDays=e.closeCommentsAfterDays,this.commentCount=e.commentCount,this.pendingCommentCount=e.pendingCommentCount,this.state=e.state,this.blocks=e.blocks,this.regions=e.regions,this.editors=e.editors,this.useBlocks=e.useBlocks,this.usePrimaryImage=e.usePrimaryImage,this.useExcerpt=e.useExcerpt,this.useHtmlExcerpt=e.useHtmlExcerpt,this.isCopy=e.isCopy,this.isScheduled=e.isScheduled,this.selectedRoute=e.selectedRoute,this.routes=e.routes,this.permissions=e.permissions,this.primaryImage=e.primaryImage,this.selectedPermissions=e.selectedPermissions,this.useBlocks?this.selectedRegion={uid:"uid-blocks",name:null,icon:null}:this.editors.length>0?this.selectedRegion=this.editors[0]:this.contentRegions.length>0&&(this.selectedRegion=this.contentRegions[0].meta)},load:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/page/"+e).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},create:function(e,t){var i=this;fetch(piranha.baseUrl+"manager/api/page/create/"+e+"/"+t).then(function(e){return e.json()}).then(function(e){i.bind(e)}).catch(function(e){console.log("error:",e)})},createrelative:function(e,t,i){var n=this;fetch(piranha.baseUrl+"manager/api/page/createrelative/"+e+"/"+t+"/"+i).then(function(e){return e.json()}).then(function(e){n.bind(e)}).catch(function(e){console.log("error:",e)})},copyrelative:function(e,t,i){var n=this;fetch(piranha.baseUrl+"manager/api/page/copyrelative/"+e+"/"+t+"/"+i).then(function(e){return e.json()}).then(function(e){n.bind(e)}).catch(function(e){console.log("error:",e)})},doHotKeys(e){83===e.keyCode&&e.ctrlKey&&(e.preventDefault(),this.saveDraft())},save:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/page/save")},saveDraft:function(){this.savingDraft=!0,this.saveInternal(piranha.baseUrl+"manager/api/page/save/draft")},unpublish:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/page/save/unpublish")},saveInternal:function(e){var t=this,i={id:t.id,siteId:t.siteId,parentId:t.parentId,originalId:t.originalId,sortOrder:t.sortOrder,typeId:t.typeId,title:t.title,navigationTitle:t.navigationTitle,slug:t.slug,metaTitle:t.metaTitle,metaKeywords:t.metaKeywords,metaDescription:t.metaDescription,metaIndex:t.metaIndex,metaFollow:t.metaFollow,metaPriority:t.metaPriority,ogTitle:t.ogTitle,ogDescription:t.ogDescription,ogImage:{id:t.ogImage.id},excerpt:t.excerpt,isHidden:t.isHidden,published:t.published,publishedTime:t.publishedTime,redirectUrl:t.redirectUrl,redirectType:t.redirectType,enableComments:t.enableComments,closeCommentsAfterDays:t.closeCommentsAfterDays,isCopy:t.isCopy,blocks:JSON.parse(JSON.stringify(t.blocks)),regions:JSON.parse(JSON.stringify(t.regions)),selectedRoute:t.selectedRoute,selectedPermissions:t.selectedPermissions,primaryImage:{id:t.primaryImage.id}};fetch(e,{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){var i=t.state;t.id=e.id,t.slug=e.slug,t.published=e.published,t.publishedTime=e.publishedTime,t.state=e.state,t.isCopy=e.isCopy,t.selectedRoute=e.selectedRoute,"new"===i&&"new"!==e.state&&window.history.replaceState({state:"created"},"Edit page",piranha.baseUrl+"manager/page/edit/"+e.id),piranha.notifications.push(e.status),t.saving=!1,t.savingDraft=!1,t.eventBus.$emit("onSaved",t.state)}).catch(function(e){console.log("error:",e)})},revert:function(){var e=this;fetch(piranha.baseUrl+"manager/api/page/revert",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(t){e.bind(t),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},detach:function(){var e=this;fetch(piranha.baseUrl+"manager/api/page/detach",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(t){e.bind(t),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},remove:function(){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/page/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),window.location=piranha.baseUrl+"manager/pages"}).catch(function(e){console.log("error:",e)})}})},addBlock:function(e,t){fetch(piranha.baseUrl+"manager/api/content/block/"+e).then(function(e){return e.json()}).then(function(e){piranha.pageedit.blocks.splice(t,0,e.body)}).catch(function(e){console.log("error:",e)})},moveBlock:function(e,t){this.blocks.splice(t,0,this.blocks.splice(e,1)[0])},collapseBlock:function(e){e.meta.isCollapsed=!e.meta.isCollapsed},removeBlock:function(e){var t=this.blocks.indexOf(e);-1!==t&&this.blocks.splice(t,1)},updateBlockTitle:function(e){for(var t=0;t<this.blocks.length;t++)if(this.blocks[t].meta.uid===e.uid){this.blocks[t].meta.title=e.title;break}},selectRegion:function(e){this.selectedRegion=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},selectSetting:function(e){this.selectedSetting=e,Vue.nextTick(function(){piranha.editor.refreshMarkdown()})},isCommentsOpen:function(){var e=new Date(this.published+" "+this.publishedTime);return(e=e.addDays(this.closeCommentsAfterDays))>new Date},commentsClosedDate:function(){var e=new Date(this.published+" "+this.publishedTime);return(e=e.addDays(this.closeCommentsAfterDays)).toDateString()},selectPrimaryImage:function(){null!==this.primaryImage.media?piranha.mediapicker.open(this.updatePrimaryImage,"Image",this.primaryImage.media.folderId):piranha.mediapicker.openCurrentFolder(this.updatePrimaryImage,"Image")},removePrimaryImage:function(){this.primaryImage.id=null,this.primaryImage.media=null},updatePrimaryImage:function(e){"Image"===e.type?(this.primaryImage.id=e.id,this.primaryImage.media=e):console.log("No image was selected")},onExcerptBlur:function(e){this.useHtmlExcerpt?this.excerpt=tinyMCE.activeEditor.getContent():this.excerpt=e.target.innerHTML}},created:function(){},updated:function(){this.loading?(sortable("#content-blocks",{handle:".handle",items:":not(.unsortable)"})[0].addEventListener("sortupdate",function(e){piranha.pageedit.moveBlock(e.detail.origin.index,e.detail.destination.index)}),piranha.editor.addInline("excerpt-body","excerpt-toolbar")):(sortable("#content-blocks","disable"),sortable("#content-blocks","enable")),this.loading=!1},components:{datepicker:vuejsDatepicker}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.pagelist.js+6 −4 modified@@ -57,7 +57,11 @@ piranha.pagelist = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/page/delete/" + id) + fetch(piranha.baseUrl + "manager/api/page/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result); @@ -78,9 +82,7 @@ piranha.pagelist = new Vue({ callback: function (l, e) { fetch(piranha.baseUrl + "manager/api/page/move", { method: "post", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ id: $(e).attr("data-id"), items: $(l).nestable("serialize")
core/Piranha.Manager/assets/dist/js/piranha.pagelist.min.js+1 −1 modified@@ -1 +1 @@ -Vue.component("pagecopy-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }">\n <div class="sitemap-item expanded">\n <div class="link" :class="{ readonly: item.isCopy }">\n <a v-if="!item.isCopy" :href="piranha.baseUrl + \'manager/page/copyrelative/\' + item.id + \'/\' + piranha.pagelist.addPageId + \'/\' + piranha.pagelist.addAfter">\n {{ item.title }}\n </a>\n <a href="#" v-else>\n {{ item.title }}\n <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n </a>\n <div class="content-blocker"></div>\n </div>\n <div class="type d-none d-md-block">\n {{ item.typeName }}\n </div>\n </div>\n <ol class="dd-list" v-if="item.items.length > 0">\n <pagecopy-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child"></pagecopy-item>\n </ol>\n</li>\n'}),Vue.component("sitemap-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }" :data-id="item.id">\n <div class="sitemap-item" :class="{ dimmed: item.isUnpublished || item.isScheduled }">\n <div class="handle dd-handle"><i class="fas fa-ellipsis-v"></i></div>\n <div class="link">\n <span class="actions">\n <a v-if="item.items.length > 0 && item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-minus"></i></a>\n <a v-if="item.items.length > 0 && !item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-plus"></i></a>\n </span>\n <a v-if="piranha.permissions.pages.edit" :href="piranha.baseUrl + item.editUrl + item.id">\n <span>{{ item.title }}</span>\n <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n </a>\n <span v-else class="title">\n <span>{{ item.title }}</span>\n <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n </span>\n </div>\n <div class="type d-none d-md-block">{{ item.typeName }}</div>\n <div class="date d-none d-lg-block">{{ item.published }}</div>\n <div class="actions">\n <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, true)"><i class="fas fa-angle-down"></i></a>\n <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, false)"><i class="fas fa-angle-right"></i></a>\n <a v-if="piranha.permissions.pages.delete && item.items.length === 0" v-on:click.prevent="piranha.pagelist.remove(item.id)" class="danger" href="#"><i class="fas fa-trash"></i></a>\n </div>\n </div>\n <ol v-if="item.items.length > 0" class="dd-list">\n <sitemap-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child">\n </sitemap-item>\n </ol>\n</li>\n'}),piranha.pagelist=new Vue({el:"#pagelist",data:{loading:!0,updateBindings:!1,items:[],sites:[],pageTypes:[],addSiteId:null,addSiteTitle:null,addPageId:null,addAfter:!0},methods:{load:function(){var e=this;piranha.permissions.load(function(){fetch(piranha.baseUrl+"manager/api/page/list").then(function(e){return e.json()}).then(function(i){e.sites=i.sites,e.pageTypes=i.pageTypes,e.updateBindings=!0}).catch(function(e){console.log("error:",e)})})},remove:function(e){var i=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/page/delete/"+e).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),i.load()}).catch(function(e){console.log("error:",e)})}})},bind:function(){var e=this;$(".sitemap-container").each(function(i,s){$(s).nestable({maxDepth:100,group:i,callback:function(i,s){fetch(piranha.baseUrl+"manager/api/page/move",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:$(s).attr("data-id"),items:$(i).nestable("serialize")})}).then(function(e){return e.json()}).then(function(i){piranha.notifications.push(i.status),"success"===i.status.type&&($(".sitemap-container").nestable("destroy"),e.sites=[],Vue.nextTick(function(){e.sites=i.sites,Vue.nextTick(function(){e.bind()})}))}).catch(function(e){console.log("error:",e)})}})})},add:function(e,i,s){var a=this;a.addSiteId=e,a.addPageId=i,a.addAfter=s,a.sites.forEach(function(i){i.id===e&&(a.addSiteTitle=i.title)}),$("#pageAddModal").modal("show")},selectSite:function(e){var i=this;i.addSiteId=e,i.sites.forEach(function(s){s.id===e&&(i.addSiteTitle=s.title)})},collapse:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!1)},expand:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!0)},changeVisibility:function(e,i){e.isExpanded=i;for(var s=0;s<e.items.length;s++)this.changeVisibility(e.items[s],i)}},created:function(){},updated:function(){this.updateBindings&&(this.bind(),this.updateBindings=!1),this.loading=!1}}); \ No newline at end of file +Vue.component("pagecopy-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }">\n <div class="sitemap-item expanded">\n <div class="link" :class="{ readonly: item.isCopy }">\n <a v-if="!item.isCopy" :href="piranha.baseUrl + \'manager/page/copyrelative/\' + item.id + \'/\' + piranha.pagelist.addPageId + \'/\' + piranha.pagelist.addAfter">\n {{ item.title }}\n </a>\n <a href="#" v-else>\n {{ item.title }}\n <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n </a>\n <div class="content-blocker"></div>\n </div>\n <div class="type d-none d-md-block">\n {{ item.typeName }}\n </div>\n </div>\n <ol class="dd-list" v-if="item.items.length > 0">\n <pagecopy-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child"></pagecopy-item>\n </ol>\n</li>\n'}),Vue.component("sitemap-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }" :data-id="item.id">\n <div class="sitemap-item" :class="{ dimmed: item.isUnpublished || item.isScheduled }">\n <div class="handle dd-handle"><i class="fas fa-ellipsis-v"></i></div>\n <div class="link">\n <span class="actions">\n <a v-if="item.items.length > 0 && item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-minus"></i></a>\n <a v-if="item.items.length > 0 && !item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-plus"></i></a>\n </span>\n <a v-if="piranha.permissions.pages.edit" :href="piranha.baseUrl + item.editUrl + item.id">\n <span>{{ item.title }}</span>\n <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n </a>\n <span v-else class="title">\n <span>{{ item.title }}</span>\n <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n </span>\n </div>\n <div class="type d-none d-md-block">{{ item.typeName }}</div>\n <div class="date d-none d-lg-block">{{ item.published }}</div>\n <div class="actions">\n <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, true)"><i class="fas fa-angle-down"></i></a>\n <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, false)"><i class="fas fa-angle-right"></i></a>\n <a v-if="piranha.permissions.pages.delete && item.items.length === 0" v-on:click.prevent="piranha.pagelist.remove(item.id)" class="danger" href="#"><i class="fas fa-trash"></i></a>\n </div>\n </div>\n <ol v-if="item.items.length > 0" class="dd-list">\n <sitemap-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child">\n </sitemap-item>\n </ol>\n</li>\n'}),piranha.pagelist=new Vue({el:"#pagelist",data:{loading:!0,updateBindings:!1,items:[],sites:[],pageTypes:[],addSiteId:null,addSiteTitle:null,addPageId:null,addAfter:!0},methods:{load:function(){var e=this;piranha.permissions.load(function(){fetch(piranha.baseUrl+"manager/api/page/list").then(function(e){return e.json()}).then(function(i){e.sites=i.sites,e.pageTypes=i.pageTypes,e.updateBindings=!0}).catch(function(e){console.log("error:",e)})})},remove:function(e){var i=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/page/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e)}).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),i.load()}).catch(function(e){console.log("error:",e)})}})},bind:function(){var e=this;$(".sitemap-container").each(function(i,s){$(s).nestable({maxDepth:100,group:i,callback:function(i,s){fetch(piranha.baseUrl+"manager/api/page/move",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify({id:$(s).attr("data-id"),items:$(i).nestable("serialize")})}).then(function(e){return e.json()}).then(function(i){piranha.notifications.push(i.status),"success"===i.status.type&&($(".sitemap-container").nestable("destroy"),e.sites=[],Vue.nextTick(function(){e.sites=i.sites,Vue.nextTick(function(){e.bind()})}))}).catch(function(e){console.log("error:",e)})}})})},add:function(e,i,s){var a=this;a.addSiteId=e,a.addPageId=i,a.addAfter=s,a.sites.forEach(function(i){i.id===e&&(a.addSiteTitle=i.title)}),$("#pageAddModal").modal("show")},selectSite:function(e){var i=this;i.addSiteId=e,i.sites.forEach(function(s){s.id===e&&(i.addSiteTitle=s.title)})},collapse:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!1)},expand:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!0)},changeVisibility:function(e,i){e.isExpanded=i;for(var s=0;s<e.items.length;s++)this.changeVisibility(e.items[s],i)}},created:function(){},updated:function(){this.updateBindings&&(this.bind(),this.updateBindings=!1),this.loading=!1}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.postedit.js+29 −22 modified@@ -246,9 +246,7 @@ piranha.postedit = new Vue({ fetch(route, { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -278,27 +276,32 @@ piranha.postedit = new Vue({ revert: function () { var self = this; - fetch(piranha.baseUrl + "manager/api/post/revert/" + self.id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/post/revert", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - Vue.nextTick(function () { - $("#selectedCategory").select2({ - tags: true, - selectOnClose: true, - placeholder: piranha.resources.texts.addCategory - }); - $("#selectedTags").select2({ - tags: true, - selectOnClose: false, - placeholder: piranha.resources.texts.addTags - }); + Vue.nextTick(function () { + $("#selectedCategory").select2({ + tags: true, + selectOnClose: true, + placeholder: piranha.resources.texts.addCategory + }); + $("#selectedTags").select2({ + tags: true, + selectOnClose: false, + placeholder: piranha.resources.texts.addTags }); + }); - piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); + piranha.notifications.push(result.status); + }) + .catch(function (error) { + console.log("error:", error ); }); }, remove: function () { @@ -311,7 +314,11 @@ piranha.postedit = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/post/delete/" + self.id) + fetch(piranha.baseUrl + "manager/api/post/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/dist/js/piranha.postedit.min.js+1 −1 modified@@ -1 +1 @@ -piranha.postedit=new Vue({el:"#postedit",data:{loading:!0,id:null,blogId:null,typeId:null,title:null,slug:null,metaTitle:null,metaKeywords:null,metaDescription:null,metaIndex:null,metaFollow:null,metaPriority:null,ogTitle:null,ogDescription:null,ogImage:{id:null,media:null},excerpt:null,published:null,redirectUrl:null,redirectType:null,enableComments:null,closeCommentsAfterDays:null,commentCount:null,pendingCommentCount:0,state:"new",categories:[],tags:[],blocks:[],regions:[],editors:[],useBlocks:!0,usePrimaryImage:!0,useExcerpt:!0,useHtmlExcerpt:!0,permissions:[],primaryImage:{id:null,media:null},isScheduled:!1,selectedPermissions:[],saving:!1,savingDraft:!1,selectedRegion:{uid:"uid-blocks",name:null,icon:null},selectedSetting:"uid-settings",selectedCategory:null,selectedTags:[],selectedRoute:null,routes:[]},computed:{contentRegions:function(){return this.regions.filter(function(e){return"setting"!=e.meta.display&&"hidden"!=e.meta.display})},settingRegions:function(){return this.regions.filter(function(e){return"setting"===e.meta.display})},primaryImageUrl:function(){return null!=this.primaryImage.media?piranha.utils.formatUrl(this.primaryImage.media.publicUrl):piranha.utils.formatUrl("~/manager/assets/img/empty-image.png")},isExcerptEmpty:function(){return piranha.utils.isEmptyText(this.excerpt)},metaPriorityDescription:function(){var e=piranha.resources.texts.important;return this.metaPriority<=.3?e=piranha.resources.texts.low:this.metaPriority<=.6?e=piranha.resources.texts.medium:this.metaPriority<=.9&&(e=piranha.resources.texts.high),e+" ("+this.metaPriority+")"}},mounted(){document.addEventListener("keydown",this.doHotKeys)},beforeDestroy(){document.removeEventListener("keydown",this.doHotKeys)},methods:{bind:function(e){this.id=e.id,this.blogId=e.blogId,this.typeId=e.typeId,this.title=e.title,this.slug=e.slug,this.metaTitle=e.metaTitle,this.metaKeywords=e.metaKeywords,this.metaDescription=e.metaDescription,this.metaIndex=e.metaIndex,this.metaFollow=e.metaFollow,this.metaPriority=e.metaPriority,this.ogTitle=e.ogTitle,this.ogDescription=e.ogDescription,this.ogImage=e.ogImage,this.excerpt=e.excerpt,this.published=e.published,this.redirectUrl=e.redirectUrl,this.redirectType=e.redirectType,this.enableComments=e.enableComments,this.closeCommentsAfterDays=e.closeCommentsAfterDays,this.commentCount=e.commentCount,this.pendingCommentCount=e.pendingCommentCount,this.state=e.state,this.blocks=e.blocks,this.regions=e.regions,this.editors=e.editors,this.categories=e.categories,this.tags=e.tags,this.useBlocks=e.useBlocks,this.usePrimaryImage=e.usePrimaryImage,this.useExcerpt=e.useExcerpt,this.useHtmlExcerpt=e.useHtmlExcerpt,this.selectedCategory=e.selectedCategory,this.selectedTags=e.selectedTags,this.selectedRoute=e.selectedRoute,this.routes=e.routes,this.permissions=e.permissions,this.primaryImage=e.primaryImage,this.isScheduled=e.isScheduled,this.selectedPermissions=e.selectedPermissions,this.useBlocks?this.selectedRegion={uid:"uid-blocks",name:null,icon:null}:this.editors.length>0?this.selectedRegion=this.editors[0]:this.contentRegions.length>0&&(this.selectedRegion=this.contentRegions[0].meta)},load:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/post/"+e).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},create:function(e,t){var i=this;fetch(piranha.baseUrl+"manager/api/post/create/"+e+"/"+t).then(function(e){return e.json()}).then(function(e){i.bind(e)}).catch(function(e){console.log("error:",e)})},doHotKeys(e){83===e.keyCode&&e.ctrlKey&&(e.preventDefault(),this.saveDraft())},save:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/post/save")},saveDraft:function(){this.savingDraft=!0,this.saveInternal(piranha.baseUrl+"manager/api/post/save/draft")},unpublish:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/post/save/unpublish")},saveInternal:function(e){var t=this,i={id:t.id,blogId:t.blogId,typeId:t.typeId,primaryImage:{id:t.primaryImage.id},title:t.title,slug:t.slug,metaTitle:t.metaTitle,metaKeywords:t.metaKeywords,metaDescription:t.metaDescription,metaIndex:t.metaIndex,metaFollow:t.metaFollow,metaPriority:t.metaPriority,ogTitle:t.ogTitle,ogDescription:t.ogDescription,ogImage:{id:t.ogImage.id},excerpt:t.excerpt,published:t.published,redirectUrl:t.redirectUrl,redirectType:t.redirectType,enableComments:t.enableComments,closeCommentsAfterDays:t.closeCommentsAfterDays,blocks:JSON.parse(JSON.stringify(t.blocks)),regions:JSON.parse(JSON.stringify(t.regions)),selectedCategory:t.selectedCategory,selectedTags:JSON.parse(JSON.stringify(t.selectedTags)),selectedRoute:t.selectedRoute,selectedPermissions:t.selectedPermissions};fetch(e,{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){var i=t.state;t.id=e.id,t.slug=e.slug,t.published=e.published,t.state=e.state,t.selectedRoute=e.selectedRoute,"new"===i&&"new"!==e.state&&window.history.replaceState({state:"created"},"Edit post",piranha.baseUrl+"manager/post/edit/"+e.id),piranha.notifications.push(e.status),t.saving=!1,t.savingDraft=!1,t.eventBus.$emit("onSaved",t.state)}).catch(function(e){console.log("error:",e)})},revert:function(){var e=this;fetch(piranha.baseUrl+"manager/api/post/revert/"+e.id).then(function(e){return e.json()}).then(function(t){e.bind(t),Vue.nextTick(function(){$("#selectedCategory").select2({tags:!0,selectOnClose:!0,placeholder:piranha.resources.texts.addCategory}),$("#selectedTags").select2({tags:!0,selectOnClose:!1,placeholder:piranha.resources.texts.addTags})}),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},remove:function(){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePostConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/post/delete/"+e.id).then(function(e){return e.json()}).then(function(t){piranha.notifications.push(t),window.location=piranha.baseUrl+"manager/page/edit/"+e.blogId}).catch(function(e){console.log("error:",e)})}})},addBlock:function(e,t){var i=this;fetch(piranha.baseUrl+"manager/api/content/block/"+e).then(function(e){return e.json()}).then(function(e){i.blocks.splice(t,0,e.body)}).catch(function(e){console.log("error:",e)})},moveBlock:function(e,t){this.blocks.splice(t,0,this.blocks.splice(e,1)[0])},collapseBlock:function(e){e.meta.isCollapsed=!e.meta.isCollapsed},removeBlock:function(e){var t=this.blocks.indexOf(e);-1!==t&&this.blocks.splice(t,1)},updateBlockTitle:function(e){for(var t=0;t<this.blocks.length;t++)if(this.blocks[t].meta.uid===e.uid){this.blocks[t].meta.title=e.title;break}},selectRegion:function(e){this.selectedRegion=e},selectSetting:function(e){this.selectedSetting=e},isCommentsOpen:function(){var e=new Date(this.published);return(e=e.addDays(this.closeCommentsAfterDays))>new Date},commentsClosedDate:function(){var e=new Date(this.published);return(e=e.addDays(this.closeCommentsAfterDays)).toDateString()},selectPrimaryImage:function(){null!==this.primaryImage.media?piranha.mediapicker.open(this.updatePrimaryImage,"Image",this.primaryImage.media.folderId):piranha.mediapicker.openCurrentFolder(this.updatePrimaryImage,"Image")},removePrimaryImage:function(){this.primaryImage.id=null,this.primaryImage.media=null},updatePrimaryImage:function(e){"Image"===e.type?(this.primaryImage.id=e.id,this.primaryImage.media=e):console.log("No image was selected")},onExcerptBlur:function(e){this.useHtmlExcerpt?this.excerpt=tinyMCE.activeEditor.getContent():this.excerpt=e.target.innerHTML}},created:function(){},updated:function(){var e=this;this.loading?(sortable("#content-blocks",{handle:".handle",items:":not(.unsortable)"})[0].addEventListener("sortupdate",function(t){e.moveBlock(t.detail.origin.index,t.detail.destination.index)}),$("#selectedCategory").select2({tags:!0,selectOnClose:!0,placeholder:piranha.resources.texts.addCategory}),$("#selectedCategory").on("change",function(){var t=$(this).find("option:selected").text();e.selectedCategory=t}),$("#selectedTags").select2({tags:!0,selectOnClose:!1,placeholder:piranha.resources.texts.addTags}),$("#selectedTags").on("change",function(){var t=$(this).find("option:selected");e.selectedTags=[];for(var i=0;i<t.length;i++)e.selectedTags.push(t[i].text)}),piranha.editor.addInline("excerpt-body","excerpt-toolbar")):(sortable("#content-blocks","disable"),sortable("#content-blocks","enable")),this.loading=!1},components:{datepicker:vuejsDatepicker}}); \ No newline at end of file +piranha.postedit=new Vue({el:"#postedit",data:{loading:!0,id:null,blogId:null,typeId:null,title:null,slug:null,metaTitle:null,metaKeywords:null,metaDescription:null,metaIndex:null,metaFollow:null,metaPriority:null,ogTitle:null,ogDescription:null,ogImage:{id:null,media:null},excerpt:null,published:null,redirectUrl:null,redirectType:null,enableComments:null,closeCommentsAfterDays:null,commentCount:null,pendingCommentCount:0,state:"new",categories:[],tags:[],blocks:[],regions:[],editors:[],useBlocks:!0,usePrimaryImage:!0,useExcerpt:!0,useHtmlExcerpt:!0,permissions:[],primaryImage:{id:null,media:null},isScheduled:!1,selectedPermissions:[],saving:!1,savingDraft:!1,selectedRegion:{uid:"uid-blocks",name:null,icon:null},selectedSetting:"uid-settings",selectedCategory:null,selectedTags:[],selectedRoute:null,routes:[]},computed:{contentRegions:function(){return this.regions.filter(function(e){return"setting"!=e.meta.display&&"hidden"!=e.meta.display})},settingRegions:function(){return this.regions.filter(function(e){return"setting"===e.meta.display})},primaryImageUrl:function(){return null!=this.primaryImage.media?piranha.utils.formatUrl(this.primaryImage.media.publicUrl):piranha.utils.formatUrl("~/manager/assets/img/empty-image.png")},isExcerptEmpty:function(){return piranha.utils.isEmptyText(this.excerpt)},metaPriorityDescription:function(){var e=piranha.resources.texts.important;return this.metaPriority<=.3?e=piranha.resources.texts.low:this.metaPriority<=.6?e=piranha.resources.texts.medium:this.metaPriority<=.9&&(e=piranha.resources.texts.high),e+" ("+this.metaPriority+")"}},mounted(){document.addEventListener("keydown",this.doHotKeys)},beforeDestroy(){document.removeEventListener("keydown",this.doHotKeys)},methods:{bind:function(e){this.id=e.id,this.blogId=e.blogId,this.typeId=e.typeId,this.title=e.title,this.slug=e.slug,this.metaTitle=e.metaTitle,this.metaKeywords=e.metaKeywords,this.metaDescription=e.metaDescription,this.metaIndex=e.metaIndex,this.metaFollow=e.metaFollow,this.metaPriority=e.metaPriority,this.ogTitle=e.ogTitle,this.ogDescription=e.ogDescription,this.ogImage=e.ogImage,this.excerpt=e.excerpt,this.published=e.published,this.redirectUrl=e.redirectUrl,this.redirectType=e.redirectType,this.enableComments=e.enableComments,this.closeCommentsAfterDays=e.closeCommentsAfterDays,this.commentCount=e.commentCount,this.pendingCommentCount=e.pendingCommentCount,this.state=e.state,this.blocks=e.blocks,this.regions=e.regions,this.editors=e.editors,this.categories=e.categories,this.tags=e.tags,this.useBlocks=e.useBlocks,this.usePrimaryImage=e.usePrimaryImage,this.useExcerpt=e.useExcerpt,this.useHtmlExcerpt=e.useHtmlExcerpt,this.selectedCategory=e.selectedCategory,this.selectedTags=e.selectedTags,this.selectedRoute=e.selectedRoute,this.routes=e.routes,this.permissions=e.permissions,this.primaryImage=e.primaryImage,this.isScheduled=e.isScheduled,this.selectedPermissions=e.selectedPermissions,this.useBlocks?this.selectedRegion={uid:"uid-blocks",name:null,icon:null}:this.editors.length>0?this.selectedRegion=this.editors[0]:this.contentRegions.length>0&&(this.selectedRegion=this.contentRegions[0].meta)},load:function(e){var t=this;fetch(piranha.baseUrl+"manager/api/post/"+e).then(function(e){return e.json()}).then(function(e){t.bind(e)}).catch(function(e){console.log("error:",e)})},create:function(e,t){var i=this;fetch(piranha.baseUrl+"manager/api/post/create/"+e+"/"+t).then(function(e){return e.json()}).then(function(e){i.bind(e)}).catch(function(e){console.log("error:",e)})},doHotKeys(e){83===e.keyCode&&e.ctrlKey&&(e.preventDefault(),this.saveDraft())},save:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/post/save")},saveDraft:function(){this.savingDraft=!0,this.saveInternal(piranha.baseUrl+"manager/api/post/save/draft")},unpublish:function(){this.saving=!0,this.saveInternal(piranha.baseUrl+"manager/api/post/save/unpublish")},saveInternal:function(e){var t=this,i={id:t.id,blogId:t.blogId,typeId:t.typeId,primaryImage:{id:t.primaryImage.id},title:t.title,slug:t.slug,metaTitle:t.metaTitle,metaKeywords:t.metaKeywords,metaDescription:t.metaDescription,metaIndex:t.metaIndex,metaFollow:t.metaFollow,metaPriority:t.metaPriority,ogTitle:t.ogTitle,ogDescription:t.ogDescription,ogImage:{id:t.ogImage.id},excerpt:t.excerpt,published:t.published,redirectUrl:t.redirectUrl,redirectType:t.redirectType,enableComments:t.enableComments,closeCommentsAfterDays:t.closeCommentsAfterDays,blocks:JSON.parse(JSON.stringify(t.blocks)),regions:JSON.parse(JSON.stringify(t.regions)),selectedCategory:t.selectedCategory,selectedTags:JSON.parse(JSON.stringify(t.selectedTags)),selectedRoute:t.selectedRoute,selectedPermissions:t.selectedPermissions};fetch(e,{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){var i=t.state;t.id=e.id,t.slug=e.slug,t.published=e.published,t.state=e.state,t.selectedRoute=e.selectedRoute,"new"===i&&"new"!==e.state&&window.history.replaceState({state:"created"},"Edit post",piranha.baseUrl+"manager/post/edit/"+e.id),piranha.notifications.push(e.status),t.saving=!1,t.savingDraft=!1,t.eventBus.$emit("onSaved",t.state)}).catch(function(e){console.log("error:",e)})},revert:function(){var e=this;fetch(piranha.baseUrl+"manager/api/post/revert",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(t){e.bind(t),Vue.nextTick(function(){$("#selectedCategory").select2({tags:!0,selectOnClose:!0,placeholder:piranha.resources.texts.addCategory}),$("#selectedTags").select2({tags:!0,selectOnClose:!1,placeholder:piranha.resources.texts.addTags})}),piranha.notifications.push(t.status)}).catch(function(e){console.log("error:",e)})},remove:function(){var e=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePostConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/post/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(t){piranha.notifications.push(t),window.location=piranha.baseUrl+"manager/page/edit/"+e.blogId}).catch(function(e){console.log("error:",e)})}})},addBlock:function(e,t){var i=this;fetch(piranha.baseUrl+"manager/api/content/block/"+e).then(function(e){return e.json()}).then(function(e){i.blocks.splice(t,0,e.body)}).catch(function(e){console.log("error:",e)})},moveBlock:function(e,t){this.blocks.splice(t,0,this.blocks.splice(e,1)[0])},collapseBlock:function(e){e.meta.isCollapsed=!e.meta.isCollapsed},removeBlock:function(e){var t=this.blocks.indexOf(e);-1!==t&&this.blocks.splice(t,1)},updateBlockTitle:function(e){for(var t=0;t<this.blocks.length;t++)if(this.blocks[t].meta.uid===e.uid){this.blocks[t].meta.title=e.title;break}},selectRegion:function(e){this.selectedRegion=e},selectSetting:function(e){this.selectedSetting=e},isCommentsOpen:function(){var e=new Date(this.published);return(e=e.addDays(this.closeCommentsAfterDays))>new Date},commentsClosedDate:function(){var e=new Date(this.published);return(e=e.addDays(this.closeCommentsAfterDays)).toDateString()},selectPrimaryImage:function(){null!==this.primaryImage.media?piranha.mediapicker.open(this.updatePrimaryImage,"Image",this.primaryImage.media.folderId):piranha.mediapicker.openCurrentFolder(this.updatePrimaryImage,"Image")},removePrimaryImage:function(){this.primaryImage.id=null,this.primaryImage.media=null},updatePrimaryImage:function(e){"Image"===e.type?(this.primaryImage.id=e.id,this.primaryImage.media=e):console.log("No image was selected")},onExcerptBlur:function(e){this.useHtmlExcerpt?this.excerpt=tinyMCE.activeEditor.getContent():this.excerpt=e.target.innerHTML}},created:function(){},updated:function(){var e=this;this.loading?(sortable("#content-blocks",{handle:".handle",items:":not(.unsortable)"})[0].addEventListener("sortupdate",function(t){e.moveBlock(t.detail.origin.index,t.detail.destination.index)}),$("#selectedCategory").select2({tags:!0,selectOnClose:!0,placeholder:piranha.resources.texts.addCategory}),$("#selectedCategory").on("change",function(){var t=$(this).find("option:selected").text();e.selectedCategory=t}),$("#selectedTags").select2({tags:!0,selectOnClose:!1,placeholder:piranha.resources.texts.addTags}),$("#selectedTags").on("change",function(){var t=$(this).find("option:selected");e.selectedTags=[];for(var i=0;i<t.length;i++)e.selectedTags.push(t[i].text)}),piranha.editor.addInline("excerpt-body","excerpt-toolbar")):(sortable("#content-blocks","disable"),sortable("#content-blocks","enable")),this.loading=!1},components:{datepicker:vuejsDatepicker}}); \ No newline at end of file
core/Piranha.Manager/assets/dist/js/piranha.siteedit.js+10 −10 modified@@ -85,9 +85,7 @@ piranha.siteedit = new Vue({ fetch(piranha.baseUrl + "manager/api/site/save", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -104,9 +102,7 @@ piranha.siteedit = new Vue({ fetch(piranha.baseUrl + "manager/api/site/savecontent", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(content) }) .then(function (contentResponse) { return contentResponse.json(); }) @@ -121,7 +117,13 @@ piranha.siteedit = new Vue({ self.callback = null; } } else { - piranha.notifications.push(contentResult); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(contentResult); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } } }) .catch(function (error) { @@ -216,9 +218,7 @@ piranha.siteedit = new Vue({ fetch(piranha.baseUrl + "manager/api/site/delete", { method: "delete", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(self.id) }) .then(function (response) { return response.json(); })
core/Piranha.Manager/assets/dist/js/piranha.siteedit.min.js+1 −1 modified@@ -1 +1 @@ -piranha.siteedit=new Vue({el:"#siteedit",data:{loading:!0,id:null,typeId:null,languageId:null,title:null,internalId:null,culture:null,description:null,logo:{id:null,media:null},hostnames:null,isDefault:!1,siteTypes:[],languages:[],regions:[],isNew:!1,isConfirm:!1,confirmTitle:null,selectedRegion:{uid:"uid-settings",name:null,icon:null},callback:null},methods:{load:function(e){self=this,fetch(piranha.baseUrl+"manager/api/site/"+e).then(function(e){return e.json()}).then(function(e){self.id=e.id,self.typeId=e.typeId,self.languageId=e.languageId,self.title=e.title,self.internalId=e.internalId,self.culture=e.culture,self.description=e.description,self.logo=e.logo,self.hostnames=e.hostnames,self.isDefault=e.isDefault,self.siteTypes=e.siteTypes,self.languages=e.languages}).catch(function(e){console.log("error:",e)}),fetch(piranha.baseUrl+"manager/api/site/content/"+e).then(function(e){return e.json()}).then(function(e){self.regions=e.regions}).catch(function(e){console.log("error:",e)})},save:function(){var e=document.getElementById("siteForm");if(!1!==e.checkValidity()){var t=this,i={id:this.id,typeId:this.typeId,languageId:this.languageId,title:this.title,internalId:this.internalId,culture:this.culture,description:this.description,logo:this.logo,hostnames:this.hostnames,isDefault:this.isDefault};fetch(piranha.baseUrl+"manager/api/site/save",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){if("success"===e.type)if(null!=t.id&&null!=t.typeId){var i={id:t.id,typeId:t.typeId,title:t.title,regions:JSON.parse(JSON.stringify(t.regions))};fetch(piranha.baseUrl+"manager/api/site/savecontent",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(i){"success"===i.type?(piranha.notifications.push(e),$("#siteedit").modal("hide"),t.callback&&(t.callback(),t.callback=null)):piranha.notifications.push(i)}).catch(function(e){console.log("error:",e)})}else $("#siteedit").modal("hide"),t.callback&&(t.callback(),t.callback=null)}).catch(function(e){console.log("error:",e)})}else e.classList.add("was-validated")},open:function(e,t){document.getElementById("siteForm").classList.remove("was-validated"),this.callback=t,this.isNew=!1,this.selectedRegion={uid:"uid-settings",name:null,icon:null},this.isConfirm=!1,this.confirmTitle=null,this.load(e),$("#siteedit").modal("show"),$("#sitetitle").focus()},create:function(e){var t=this;document.getElementById("siteForm").classList.remove("was-validated"),fetch(piranha.baseUrl+"manager/api/site/create").then(function(e){return e.json()}).then(function(i){t.id=i.id,t.typeId=i.typeId,t.title=i.title,t.internalId=i.internalId,t.culture=i.culture,t.description=i.description,t.hostnames=i.hostnames,t.isDefault=i.isDefault,t.siteTypes=i.siteTypes,t.languages=i.languages,t.isNew=!0,t.callback=e,t.selectedRegion={uid:"uid-settings",name:null,icon:null}}).catch(function(e){console.log("error:",e)}),$("#siteedit").modal("show"),$("#sitetitle").focus()},confirm:function(){this.isConfirm=!0},cancel:function(){this.isConfirm=!1,this.confirmTitle=null},remove:function(){this.isConfirm=!1,this.confirmTitle=null;var e=this;fetch(piranha.baseUrl+"manager/api/site/delete",{method:"delete",headers:{"Content-Type":"application/json"},body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(t){piranha.notifications.push(t),"success"===t.type&&($("#siteedit").modal("hide"),e.callback&&(e.callback(),e.callback=null))}).catch(function(e){console.log("error:",e)})},selectRegion:function(e){this.selectedRegion=e}},updated:function(){this.loading=!1}}),$("#siteedit").on("shown.bs.modal",function(){$("#sitetitle").trigger("focus")}); \ No newline at end of file +piranha.siteedit=new Vue({el:"#siteedit",data:{loading:!0,id:null,typeId:null,languageId:null,title:null,internalId:null,culture:null,description:null,logo:{id:null,media:null},hostnames:null,isDefault:!1,siteTypes:[],languages:[],regions:[],isNew:!1,isConfirm:!1,confirmTitle:null,selectedRegion:{uid:"uid-settings",name:null,icon:null},callback:null},methods:{load:function(e){self=this,fetch(piranha.baseUrl+"manager/api/site/"+e).then(function(e){return e.json()}).then(function(e){self.id=e.id,self.typeId=e.typeId,self.languageId=e.languageId,self.title=e.title,self.internalId=e.internalId,self.culture=e.culture,self.description=e.description,self.logo=e.logo,self.hostnames=e.hostnames,self.isDefault=e.isDefault,self.siteTypes=e.siteTypes,self.languages=e.languages}).catch(function(e){console.log("error:",e)}),fetch(piranha.baseUrl+"manager/api/site/content/"+e).then(function(e){return e.json()}).then(function(e){self.regions=e.regions}).catch(function(e){console.log("error:",e)})},save:function(){var e=document.getElementById("siteForm");if(!1!==e.checkValidity()){var t=this,i={id:this.id,typeId:this.typeId,languageId:this.languageId,title:this.title,internalId:this.internalId,culture:this.culture,description:this.description,logo:this.logo,hostnames:this.hostnames,isDefault:this.isDefault};fetch(piranha.baseUrl+"manager/api/site/save",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(e){if("success"===e.type)if(null!=t.id&&null!=t.typeId){var i={id:t.id,typeId:t.typeId,title:t.title,regions:JSON.parse(JSON.stringify(t.regions))};fetch(piranha.baseUrl+"manager/api/site/savecontent",{method:"post",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(i)}).then(function(e){return e.json()}).then(function(i){"success"===i.type?(piranha.notifications.push(e),$("#siteedit").modal("hide"),t.callback&&(t.callback(),t.callback=null)):400!==e.status?piranha.notifications.push(i):piranha.notifications.unauthorized()}).catch(function(e){console.log("error:",e)})}else $("#siteedit").modal("hide"),t.callback&&(t.callback(),t.callback=null)}).catch(function(e){console.log("error:",e)})}else e.classList.add("was-validated")},open:function(e,t){document.getElementById("siteForm").classList.remove("was-validated"),this.callback=t,this.isNew=!1,this.selectedRegion={uid:"uid-settings",name:null,icon:null},this.isConfirm=!1,this.confirmTitle=null,this.load(e),$("#siteedit").modal("show"),$("#sitetitle").focus()},create:function(e){var t=this;document.getElementById("siteForm").classList.remove("was-validated"),fetch(piranha.baseUrl+"manager/api/site/create").then(function(e){return e.json()}).then(function(i){t.id=i.id,t.typeId=i.typeId,t.title=i.title,t.internalId=i.internalId,t.culture=i.culture,t.description=i.description,t.hostnames=i.hostnames,t.isDefault=i.isDefault,t.siteTypes=i.siteTypes,t.languages=i.languages,t.isNew=!0,t.callback=e,t.selectedRegion={uid:"uid-settings",name:null,icon:null}}).catch(function(e){console.log("error:",e)}),$("#siteedit").modal("show"),$("#sitetitle").focus()},confirm:function(){this.isConfirm=!0},cancel:function(){this.isConfirm=!1,this.confirmTitle=null},remove:function(){this.isConfirm=!1,this.confirmTitle=null;var e=this;fetch(piranha.baseUrl+"manager/api/site/delete",{method:"delete",headers:piranha.utils.antiForgeryHeaders(),body:JSON.stringify(e.id)}).then(function(e){return e.json()}).then(function(t){piranha.notifications.push(t),"success"===t.type&&($("#siteedit").modal("hide"),e.callback&&(e.callback(),e.callback=null))}).catch(function(e){console.log("error:",e)})},selectRegion:function(e){this.selectedRegion=e}},updated:function(){this.loading=!1}}),$("#siteedit").on("shown.bs.modal",function(){$("#sitetitle").trigger("focus")}); \ No newline at end of file
core/Piranha.Manager/assets/src/js/components/post-archive.vue+5 −1 modified@@ -113,7 +113,11 @@ export default { confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/post/delete/" + postId) + fetch(piranha.baseUrl + "manager/api/post/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(postId) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/src/js/piranha.alias.js+43 −36 modified@@ -44,43 +44,45 @@ } fetch(piranha.baseUrl + "manager/api/alias/save", { - method: "post", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - id: piranha.alias.model.id, - siteId: piranha.alias.siteId, - aliasUrl: piranha.alias.model.aliasUrl, - redirectUrl: piranha.alias.model.redirectUrl, - isPermanent: piranha.alias.model.isPermanent != null ? piranha.alias.model.isPermanent : false - }) + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify({ + id: piranha.alias.model.id, + siteId: piranha.alias.siteId, + aliasUrl: piranha.alias.model.aliasUrl, + redirectUrl: piranha.alias.model.redirectUrl, + isPermanent: piranha.alias.model.isPermanent != null ? piranha.alias.model.isPermanent : false }) - .then(function (response) { return response.json(); }) - .then(function (result) { - if (result.status.type === "success") - { - // Remove validation class - form.classList.remove("was-validated"); + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + if (result.status.type === "success") { + // Remove validation class + form.classList.remove("was-validated"); - // Close modal - $("#aliasModal").modal("hide"); + // Close modal + $("#aliasModal").modal("hide"); - // Clear modal - piranha.alias.model.id = null; - piranha.alias.model.aliasUrl = null; - piranha.alias.model.redirectUrl = null; - piranha.alias.model.isPermanent = true; + // Clear modal + piranha.alias.model.id = null; + piranha.alias.model.aliasUrl = null; + piranha.alias.model.redirectUrl = null; + piranha.alias.model.isPermanent = true; - piranha.alias.items = result.items; - } + piranha.alias.items = result.items; + } + if (result.status !== 400) { // Push status to notification hub piranha.notifications.push(result.status); - }) - .catch(function (error) { - console.log("error:", error); - }); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } + }) + .catch(function (error) { + console.log("error:", error); + }); }, remove: function (id) { var self = this; @@ -94,17 +96,22 @@ onConfirm: function () { fetch(piranha.baseUrl + "manager/api/alias/delete", { method: "delete", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(id) }) .then(function (response) { return response.json(); }) .then(function (result) { - self.items = result.items; + if (result.status.type === "success") { + self.items = result.items; + } - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error ); }); }
core/Piranha.Manager/assets/src/js/piranha.comment.js+53 −29 modified@@ -44,32 +44,50 @@ piranha.comment = new Vue({ approve: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/comment/approve/" + id + (self.contentId != null ? "/" + self.contentId : "")) - .then(function (response) { return response.json(); }) - .then(function (result) { - if (result.status) { - // Push status to notification hub - piranha.notifications.push(result.status); - } - self.contentId = result.contentId; - self.items = result.comments; + fetch(piranha.baseUrl + "manager/api/comment/approve", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify({ + id: id, + parentId: self.contentId }) - .catch(function (error) { console.log("error:", error ); }); + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + if (result.status) { + // Push status to notification hub + piranha.notifications.push(result.status); + } + self.contentId = result.contentId; + self.items = result.comments; + }) + .catch(function (error) { + console.log("error:", error ); + }); }, unapprove: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/comment/unapprove/" + id + (self.contentId != null ? "/" + self.contentId : "")) - .then(function (response) { return response.json(); }) - .then(function (result) { - if (result.status) { - // Push status to notification hub - piranha.notifications.push(result.status); - } - self.contentId = result.contentId; - self.items = result.comments; + fetch(piranha.baseUrl + "manager/api/comment/unapprove", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify({ + id: id, + parentId: self.contentId }) - .catch(function (error) { console.log("error:", error ); }); + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + if (result.status) { + // Push status to notification hub + piranha.notifications.push(result.status); + } + self.contentId = result.contentId; + self.items = result.comments; + }) + .catch(function (error) { + console.log("error:", error ); + }); }, toggleApproved: function (item) { item.isApproved = !item.isApproved; @@ -83,16 +101,22 @@ piranha.comment = new Vue({ remove: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/comment/delete/" + id) - .then(function (response) { return response.json(); }) - .then(function (result) { - // Push status to notification hub - piranha.notifications.push(result); + fetch(piranha.baseUrl + "manager/api/comment/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + // Push status to notification hub + piranha.notifications.push(result); - // Refresh the list - self.load(self.contentId); - }) - .catch(function (error) { console.log("error:", error ); }); + // Refresh the list + self.load(self.contentId); + }) + .catch(function (error) { + console.log("error:", error ); + }); }, setStatus: function (status) { this.state = status;
core/Piranha.Manager/assets/src/js/piranha.config.js+8 −5 modified@@ -56,9 +56,7 @@ piranha.config = new Vue({ fetch(piranha.baseUrl + "manager/api/config/save", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ hierarchicalPageSlugs: self.model.hierarchicalPageSlugs, expandedSitemapLevels: self.model.expandedSitemapLevels, @@ -80,8 +78,13 @@ piranha.config = new Vue({ }) .then(function (response) { return response.json(); }) .then(function (result) { - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error);
core/Piranha.Manager/assets/src/js/piranha.contentedit.js+6 −4 modified@@ -195,9 +195,7 @@ piranha.contentedit = new Vue({ fetch(route, { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -233,7 +231,11 @@ piranha.contentedit = new Vue({ onConfirm: function () { var groupId = self.groupId; - fetch(piranha.baseUrl + "manager/api/content/delete/" + self.id) + fetch(piranha.baseUrl + "manager/api/content/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/src/js/piranha.contentlist.js+5 −1 modified@@ -49,7 +49,11 @@ piranha.contentlist = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/content/delete/" + id) + fetch(piranha.baseUrl + "manager/api/content/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/src/js/piranha.dropzone.js+1 −0 modified@@ -14,6 +14,7 @@ piranha.dropzone = new function () { var defaultOptions = { paramName: 'Uploads', url: piranha.baseUrl + "manager/api/media/upload", + headers: piranha.utils.antiForgeryHeaders(false), thumbnailWidth: 70, thumbnailHeight: 70, previewsContainer: selector + " .media-list",
core/Piranha.Manager/assets/src/js/piranha.languageedit.js+23 −17 modified@@ -52,22 +52,25 @@ piranha.languageedit = new Vue({ self.loading = true; fetch(piranha.baseUrl + "manager/api/language", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ items: JSON.parse(JSON.stringify(self.items)) }) }) .then(function (response) { return response.json(); }) .then(function (result) { - //if (result.status.type === "success") - //{ + if (result.status.type === "success") { self.bind(result); - //} - - // Push status to notification hub - // piranha.notifications.push(result.status); + } + + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + self.loading = false; + } }) .catch(function (error) { console.log("error:", error); @@ -80,20 +83,23 @@ piranha.languageedit = new Vue({ self.loading = true; fetch(piranha.baseUrl + "manager/api/language/" + item.id, { method: "delete", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(item) }) .then(function (response) { return response.json(); }) .then(function (result) { - //if (result.status.type === "success") - //{ + if (result.status.type === "success") { self.bind(result); - //} + } - // Push status to notification hub - // piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + self.loading = false; + } }) .catch(function (error) { console.log("error:", error);
core/Piranha.Manager/assets/src/js/piranha.media.js+52 −31 modified@@ -115,18 +115,22 @@ piranha.media = new Vue({ fetch(piranha.baseUrl + "manager/api/media/move/" + (folderId || ""), { method: "POST", - headers: { - 'Content-Type': 'application/json' - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(selections) }) .then(function (response) { return response.json(); }) .then(function (result) { if (result.type === "success") { piranha.media.refresh(); } - // Push status to notification hub - piranha.notifications.push(result); + + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); }); }, @@ -166,7 +170,6 @@ piranha.media = new Vue({ piranha.media.load(piranha.media.currentFolderId); }, addFolder: function () { - //this.saveFolder("#mediaFolderModal", "mediaFolderForm", { this.saveFolder(null, null, { parentId: this.currentFolderId, name: this.folder.name @@ -193,9 +196,7 @@ piranha.media = new Vue({ fetch(piranha.baseUrl + "manager/api/media/folder/save", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(folder) }) .then(function (response) { return response.json(); }) @@ -215,8 +216,13 @@ piranha.media = new Vue({ self.refresh(); } - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); @@ -226,19 +232,22 @@ piranha.media = new Vue({ var self = this; fetch(piranha.baseUrl + "manager/api/media/delete", { - method: "post", - headers: { - "Content-Type": "application/json", - }, + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify([id]) }) .then(function (response) { return response.json(); }) .then(function (result) { // Refresh self.refresh(); - // Push status to notification hub - piranha.notifications.push(result); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error ); }); }, @@ -254,19 +263,22 @@ piranha.media = new Vue({ confirmText: piranha.resources.texts.delete, onConfirm: function () { fetch(piranha.baseUrl + "manager/api/media/delete", { - method: "post", - headers: { - "Content-Type": "application/json", - }, + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(selections) }) .then(function (response) { return response.json(); }) .then(function (result) { // Refresh self.refresh(); - // Push status to notification hub - piranha.notifications.push(result); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error); }); } @@ -275,18 +287,27 @@ piranha.media = new Vue({ removeFolder: function (id) { var self = this; - fetch(piranha.baseUrl + "manager/api/media/folder/delete/" + id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/media/folder/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - history.pushState({ folderId: id }, "", piranha.baseUrl + "manager/media" + (id ? "/" + id : "")); - document.title = result.currentFolderName ? result.currentFolderName : "Media"; + history.pushState({ folderId: id }, "", piranha.baseUrl + "manager/media" + (id ? "/" + id : "")); + document.title = result.currentFolderName ? result.currentFolderName : "Media"; + if (result.status !== 400) { // Push status to notification hub piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); }); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } + }) + .catch(function (error) { console.log("error:", error ); }); } }, computed: {
core/Piranha.Manager/assets/src/js/piranha.mediapicker.js+8 −5 modified@@ -148,9 +148,7 @@ piranha.mediapicker = new Vue({ if (self.folderName !== "") { fetch(piranha.baseUrl + "manager/api/media/folder/save" + (self.filter ? "?filter=" + self.filter : ""), { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ parentId: self.currentFolderId, name: self.folderName @@ -167,8 +165,13 @@ piranha.mediapicker = new Vue({ self.items = result.media; } - // Push status to notification hub - piranha.notifications.push(result.status); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(result.status); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } }) .catch(function (error) { console.log("error:", error);
core/Piranha.Manager/assets/src/js/piranha.notifications.js+7 −0 modified@@ -8,6 +8,13 @@ piranha.notifications = new Vue({ items: [], }, methods: { + unauthorized: function() { + this.push({ + type: "danger", + body: "Request sender could not be verified by the server.", + hide: true + }); + }, push: function (notification) { notification.style = {
core/Piranha.Manager/assets/src/js/piranha.pageedit.js+30 −19 modified@@ -280,9 +280,7 @@ piranha.pageedit = new Vue({ fetch(route, { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -314,29 +312,38 @@ piranha.pageedit = new Vue({ revert: function () { var self = this; - fetch(piranha.baseUrl + "manager/api/page/revert/" + self.id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/page/revert", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); + piranha.notifications.push(result.status); + }) + .catch(function (error) { + console.log("error:", error ); }); }, detach: function () { var self = this; - fetch(piranha.baseUrl + "manager/api/page/detach/" + self.id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/page/detach", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); + piranha.notifications.push(result.status); + }) + .catch(function (error) { + console.log("error:", error ); }); - }, remove: function () { var self = this; @@ -348,7 +355,11 @@ piranha.pageedit = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/page/delete/" + self.id) + fetch(piranha.baseUrl + "manager/api/page/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/src/js/piranha.pagelist.js+6 −4 modified@@ -39,7 +39,11 @@ piranha.pagelist = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/page/delete/" + id) + fetch(piranha.baseUrl + "manager/api/page/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result); @@ -60,9 +64,7 @@ piranha.pagelist = new Vue({ callback: function (l, e) { fetch(piranha.baseUrl + "manager/api/page/move", { method: "post", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify({ id: $(e).attr("data-id"), items: $(l).nestable("serialize")
core/Piranha.Manager/assets/src/js/piranha.postedit.js+29 −22 modified@@ -246,9 +246,7 @@ piranha.postedit = new Vue({ fetch(route, { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -278,27 +276,32 @@ piranha.postedit = new Vue({ revert: function () { var self = this; - fetch(piranha.baseUrl + "manager/api/post/revert/" + self.id) - .then(function (response) { return response.json(); }) - .then(function (result) { - self.bind(result); + fetch(piranha.baseUrl + "manager/api/post/revert", { + method: "post", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) + .then(function (response) { return response.json(); }) + .then(function (result) { + self.bind(result); - Vue.nextTick(function () { - $("#selectedCategory").select2({ - tags: true, - selectOnClose: true, - placeholder: piranha.resources.texts.addCategory - }); - $("#selectedTags").select2({ - tags: true, - selectOnClose: false, - placeholder: piranha.resources.texts.addTags - }); + Vue.nextTick(function () { + $("#selectedCategory").select2({ + tags: true, + selectOnClose: true, + placeholder: piranha.resources.texts.addCategory + }); + $("#selectedTags").select2({ + tags: true, + selectOnClose: false, + placeholder: piranha.resources.texts.addTags }); + }); - piranha.notifications.push(result.status); - }) - .catch(function (error) { console.log("error:", error ); + piranha.notifications.push(result.status); + }) + .catch(function (error) { + console.log("error:", error ); }); }, remove: function () { @@ -311,7 +314,11 @@ piranha.postedit = new Vue({ confirmIcon: "fas fa-trash", confirmText: piranha.resources.texts.delete, onConfirm: function () { - fetch(piranha.baseUrl + "manager/api/post/delete/" + self.id) + fetch(piranha.baseUrl + "manager/api/post/delete", { + method: "delete", + headers: piranha.utils.antiForgeryHeaders(), + body: JSON.stringify(self.id) + }) .then(function (response) { return response.json(); }) .then(function (result) { piranha.notifications.push(result);
core/Piranha.Manager/assets/src/js/piranha.siteedit.js+10 −10 modified@@ -85,9 +85,7 @@ piranha.siteedit = new Vue({ fetch(piranha.baseUrl + "manager/api/site/save", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(model) }) .then(function (response) { return response.json(); }) @@ -104,9 +102,7 @@ piranha.siteedit = new Vue({ fetch(piranha.baseUrl + "manager/api/site/savecontent", { method: "post", - headers: { - "Content-Type": "application/json", - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(content) }) .then(function (contentResponse) { return contentResponse.json(); }) @@ -121,7 +117,13 @@ piranha.siteedit = new Vue({ self.callback = null; } } else { - piranha.notifications.push(contentResult); + if (result.status !== 400) { + // Push status to notification hub + piranha.notifications.push(contentResult); + } else { + // Unauthorized request + piranha.notifications.unauthorized(); + } } }) .catch(function (error) { @@ -216,9 +218,7 @@ piranha.siteedit = new Vue({ fetch(piranha.baseUrl + "manager/api/site/delete", { method: "delete", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(self.id) }) .then(function (response) { return response.json(); })
core/Piranha.Manager/assets/src/js/piranha.utils.js+22 −1 modified@@ -14,7 +14,28 @@ piranha.utils = { }, strLength: function (str) { return str != null ? str.length : 0; - } + }, + antiForgery: function () { + const cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) { + let c = cookies[i].trim().split("="); + if (c[0] === piranha.antiForgery.cookieName) { + return c[1]; + } + } + return ""; + }, + antiForgeryHeaders: function (isJson) { + var headers = {}; + + if (isJson === undefined || isJson === true) + { + headers["Content-Type"] = "application/json"; + } + headers[piranha.antiForgery.headerName] = piranha.utils.antiForgery(); + + return headers; + } }; Date.prototype.addDays = function(days) {
core/Piranha.Manager/assets/src/scss/inc/_actions.scss+3 −1 modified@@ -3,7 +3,9 @@ .actions { white-space: nowrap; - a { + a, button { + background-color: transparent; + border: none; display: inline-block; width: 1.5rem; height: 1.5rem;
core/Piranha.Manager/assets/src/scss/inc/_notifications.scss+1 −1 modified@@ -4,7 +4,7 @@ position: fixed; left: 4rem; bottom: 0; - z-index: 2000; // TODO: verify z-index later + z-index: 20000; // TODO: verify z-index later .notification { width: 300px;
core/Piranha.Manager/Controllers/AliasApiController.cs+1 −0 modified@@ -25,6 +25,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/alias")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class AliasApiController : Controller { private readonly IApi _api;
core/Piranha.Manager/Controllers/AuthController.cs+55 −0 added@@ -0,0 +1,55 @@ +/* + * Copyright (c) .NET Foundation and Contributors + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + * https://github.com/piranhacms/piranha.core + * + */ + +using Microsoft.AspNetCore.Antiforgery; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace Piranha.Manager.Controllers +{ + [Area("Manager")] + [Route("manager/login/auth")] + [Authorize(Policy = Permission.Admin)] + [ApiController] + public sealed class AuthController : Controller + { + private readonly IAntiforgery _antiForgery; + private readonly ManagerOptions _options; + + /// <summary> + /// Default constructor. + /// </summary> + /// <param name="antiforgery">The antiforgery service</param> + /// <param name="options">The manager options</param> + public AuthController(IAntiforgery antiforgery, IOptions<ManagerOptions> options) + { + _antiForgery = antiforgery; + _options = options.Value; + } + + [Route("{returnUrl?}")] + [HttpGet] + public IActionResult SetAuthCookie(string returnUrl = null) + { + var tokens = _antiForgery.GetAndStoreTokens(HttpContext); + Response.Cookies.Append(_options.XsrfCookieName, tokens.RequestToken, new CookieOptions + { + HttpOnly = false + }); + if (!string.IsNullOrEmpty(returnUrl)) + { + return LocalRedirect(returnUrl); + } + return LocalRedirect("~/manager"); + } + } +} \ No newline at end of file
core/Piranha.Manager/Controllers/CommentApiController.cs+21 −14 modified@@ -24,8 +24,15 @@ namespace Piranha.Manager.Controllers [Route("manager/api/comment")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class CommentApiController : Controller { + public class ApprovalModel + { + public Guid Id { get; set; } + public Guid? ParentId { get; set; } + } + private readonly CommentService _service; private readonly ManagerLocalizer _localizer; @@ -50,14 +57,14 @@ public Task<CommentListModel> List(Guid? id = null) return _service.Get(id); } - [Route("approve/{id}/{parentId?}")] - [HttpGet] + [Route("approve")] + [HttpPost] [Authorize(Policy = Permission.CommentsApprove)] - public async Task<CommentListModel> Approve(Guid id, Guid? parentId = null) + public async Task<CommentListModel> Approve(ApprovalModel model) { - await _service.ApproveAsync(id); + await _service.ApproveAsync(model.Id).ConfigureAwait(false); - var result = await List(parentId); + var result = await List(model.ParentId).ConfigureAwait(false); result.Status = new StatusMessage { @@ -67,14 +74,14 @@ public async Task<CommentListModel> Approve(Guid id, Guid? parentId = null) return result; } - [Route("unapprove/{id}/{parentId?}")] - [HttpGet] + [Route("unapprove")] + [HttpPost] [Authorize(Policy = Permission.CommentsApprove)] - public async Task<CommentListModel> UnApprove(Guid id, Guid? parentId = null) + public async Task<CommentListModel> UnApprove(ApprovalModel model) { - await _service.UnApproveAsync(id); + await _service.UnApproveAsync(model.Id).ConfigureAwait(false); - var result = await List(parentId); + var result = await List(model.ParentId).ConfigureAwait(false); result.Status = new StatusMessage { @@ -84,12 +91,12 @@ public async Task<CommentListModel> UnApprove(Guid id, Guid? parentId = null) return result; } - [Route("delete/{id}")] - [HttpGet] + [Route("delete")] + [HttpDelete] [Authorize(Policy = Permission.CommentsDelete)] - public async Task<StatusMessage> Delete(Guid id) + public async Task<StatusMessage> Delete([FromBody]Guid id) { - await _service.DeleteAsync(id); + await _service.DeleteAsync(id).ConfigureAwait(false); var result = new StatusMessage {
core/Piranha.Manager/Controllers/ConfigApiController.cs+1 −0 modified@@ -22,6 +22,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/config")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class ConfigApiController : Controller { private readonly ConfigService _service;
core/Piranha.Manager/Controllers/ContentApiController.cs+4 −3 modified@@ -25,6 +25,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/content")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class ContentApiController : Controller { private readonly IApi _api; @@ -228,10 +229,10 @@ public async Task<ContentEditModel> Save(ContentEditModel model) /// </summary> /// <param name="id">The unique id</param> /// <returns>The result of the operation</returns> - [Route("delete/{id}")] - [HttpGet] + [Route("delete")] + [HttpDelete] [Authorize(Policy = Permission.ContentDelete)] - public async Task<StatusMessage> Delete(Guid id) + public async Task<StatusMessage> Delete([FromBody]Guid id) { try {
core/Piranha.Manager/Controllers/LanguageApiController.cs+51 −5 modified@@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Mvc; using Piranha.Manager.Models; using Piranha.Manager.Services; -using Piranha.Models; namespace Piranha.Manager.Controllers { @@ -25,6 +24,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/language")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class LanguageApiController : Controller { private readonly LanguageService _service; @@ -56,16 +56,62 @@ public async Task<LanguageEditModel> Get() /// <param name="model">The model</param> [Route("")] [HttpPost] - public async Task<LanguageEditModel> Save(LanguageEditModel model) + public async Task<IActionResult> Save(LanguageEditModel model) { - return await _service.Save(model); + try + { + var result = await _service.Save(model); + + result.Status = new StatusMessage + { + Type = StatusMessage.Success, + Body = _localizer.Language["The language was successfully saved"] + }; + + return Ok(result); + } + catch (Exception e) + { + var result = new LanguageEditModel(); + result.Status = new StatusMessage + { + Type = StatusMessage.Error, + Body = e.Message + }; + return BadRequest(result); + } } + /// <summary> + /// Deletes the language with the given id. + /// </summary> + /// <param name="id">The unique id</param> [Route("{id}")] [HttpDelete] - public async Task<LanguageEditModel> Delete(Guid id) + public async Task<IActionResult> Delete(Guid id) { - return await _service.Delete(id); + try + { + var result = await _service.Delete(id); + + result.Status = new StatusMessage + { + Type = StatusMessage.Success, + Body = _localizer.Language["The language was successfully deleted"] + }; + + return Ok(result); + } + catch (Exception e) + { + var result = new LanguageEditModel(); + result.Status = new StatusMessage + { + Type = StatusMessage.Error, + Body = e.Message + }; + return BadRequest(result); + } } } } \ No newline at end of file
core/Piranha.Manager/Controllers/MediaApiController.cs+5 −4 modified@@ -28,6 +28,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/media")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class MediaApiController : Controller { private readonly MediaService _service; @@ -153,10 +154,10 @@ public async Task<IActionResult> SaveFolder(MediaFolderModel model, MediaType? f } } - [Route("folder/delete/{id:Guid}")] - [HttpGet] + [Route("folder/delete")] + [HttpDelete] [Authorize(Policy = Permission.MediaDeleteFolder)] - public async Task<IActionResult> DeleteFolder(Guid id) + public async Task<IActionResult> DeleteFolder([FromBody]Guid id) { try { @@ -299,7 +300,7 @@ public async Task<IActionResult> Move([FromBody] IEnumerable<Guid> items, Guid? } [Route("delete")] - [HttpPost] + [HttpDelete] [Consumes("application/json")] [Authorize(Policy = Permission.MediaDelete)] public async Task<IActionResult> Delete([FromBody] IEnumerable<Guid> items)
core/Piranha.Manager/Controllers/ModuleApiController.cs+1 −0 modified@@ -23,6 +23,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/module")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class ModuleApiController : Controller { private readonly ModuleService _service;
core/Piranha.Manager/Controllers/PageApiController.cs+10 −9 modified@@ -26,6 +26,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/page")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class PageApiController : Controller { private readonly PageService _service; @@ -151,10 +152,10 @@ public async Task<PageEditModel> CopyRelative(Guid sourceId, Guid pageId, bool a /// </summary> /// <param name="pageId">The page id</param> /// <returns>The page edit model</returns> - [Route("detach/{pageId}")] - [HttpGet] + [Route("detach")] + [HttpPost] [Authorize(Policy = Permission.PagesEdit)] - public async Task<PageEditModel> Detach(Guid pageId) + public async Task<PageEditModel> Detach([FromBody]Guid pageId) { var model = await _service.Detach(pageId); @@ -227,10 +228,10 @@ public async Task<PageEditModel> SaveUnpublish(PageEditModel model) return ret; } - [Route("revert/{id}")] - [HttpGet] + [Route("revert")] + [HttpPost] [Authorize(Policy = Permission.PagesSave)] - public async Task<PageEditModel> Revert(Guid id) + public async Task<PageEditModel> Revert([FromBody]Guid id) { var page = await _service.GetById(id, false); @@ -257,10 +258,10 @@ public async Task<PageEditModel> Revert(Guid id) /// </summary> /// <param name="id">The unique id</param> /// <returns>The result of the operation</returns> - [Route("delete/{id}")] - [HttpGet] + [Route("delete")] + [HttpDelete] [Authorize(Policy = Permission.PagesDelete)] - public async Task<StatusMessage> Delete(Guid id) + public async Task<StatusMessage> Delete([FromBody]Guid id) { try {
core/Piranha.Manager/Controllers/PermissionApiController.cs+1 −0 modified@@ -22,6 +22,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/permissions")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class PermissionApiController : Controller { private readonly IAuthorizationService _auth;
core/Piranha.Manager/Controllers/PostApiController.cs+7 −6 modified@@ -26,6 +26,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/post")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class PostApiController : Controller { private readonly PostService _service; @@ -162,10 +163,10 @@ public async Task<PostEditModel> SaveUnpublish(PostEditModel model) return ret; } - [Route("revert/{id}")] - [HttpGet] + [Route("revert")] + [HttpPost] [Authorize(Policy = Permission.PostsSave)] - public async Task<PostEditModel> Revert(Guid id) + public async Task<PostEditModel> Revert([FromBody]Guid id) { var post = await _service.GetById(id, false); @@ -193,10 +194,10 @@ public async Task<PostEditModel> Revert(Guid id) /// </summary> /// <param name="id">The unique id</param> /// <returns>The result of the operation</returns> - [Route("delete/{id}")] - [HttpGet] + [Route("delete")] + [HttpDelete] [Authorize(Policy = Permission.PostsDelete)] - public async Task<StatusMessage> Delete(Guid id) + public async Task<StatusMessage> Delete([FromBody]Guid id) { try {
core/Piranha.Manager/Controllers/SiteApiController.cs+1 −0 modified@@ -25,6 +25,7 @@ namespace Piranha.Manager.Controllers [Route("manager/api/site")] [Authorize(Policy = Permission.Admin)] [ApiController] + [AutoValidateAntiforgeryToken] public class SiteApiController : Controller { private readonly SiteService _service;
core/Piranha.Manager/Extensions/ManagerExtensions.cs+166 −166 renamed@@ -1,166 +1,166 @@ -/* - * Copyright (c) .NET Foundation and Contributors - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - * - * https://github.com/piranhacms/piranha.core - * - */ - -using System; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; -using Newtonsoft.Json; -using Piranha.Manager; -using Piranha.Manager.Hubs; -using Piranha.Manager.Services; - -public static class ManagerModuleExtensions -{ - /// <summary> - /// Adds the Piranha manager module. - /// </summary> - /// <param name="services">The current service collection</param> - /// <returns>The services</returns> - public static IServiceCollection AddPiranhaManager(this IServiceCollection services) - { - return services.AddPiranhaManager(null); - } - - /// <summary> - /// Adds the Piranha manager module. - /// </summary> - /// <param name="services">The current service collection</param> - /// <param name="configurePolicy">The delegate that will be used to build the Piranha Manager named policies.</param> - /// <returns>The services</returns> - public static IServiceCollection AddPiranhaManager(this IServiceCollection services, Action<string, AuthorizationPolicyBuilder> configurePolicy) - { - // Add the manager module - Piranha.App.Modules.Register<Piranha.Manager.Module>(); - - // Add the manager services - services.AddScoped<AliasService>(); - services.AddScoped<CommentService>(); - services.AddScoped<ConfigService>(); - services.AddScoped<ContentService>(); - services.AddScoped<ContentTypeService>(); - services.AddScoped<LanguageService>(); - services.AddScoped<MediaService>(); - services.AddScoped<ModuleService>(); - services.AddScoped<PageService>(); - services.AddScoped<PostService>(); - services.AddScoped<SiteService>(); - - // Add localization service - services.AddScoped<ManagerLocalizer>(); - - // Add session support - services.AddSession(); - - // Add SignalR - services.AddSignalR(); - - // Setup authorization policies - services.AddAuthorization(o => - { - if (configurePolicy is not null) - { - //If custom AuthorizationOptions delegate is provided, invoke - foreach (var permission in Permission.All()) - { - o.AddPolicy(permission, configure => configurePolicy.Invoke(permission, configure)); - } - } - else - { - //Else configure default Claims based Policies, using Piranha nested permissions structure - //Add root (Admin) policy and Claims - o.AddPolicy(Permission.PermissionsStructure.PermissionName, configure => { configure.RequireClaim(Permission.PermissionsStructure.PermissionName, Permission.PermissionsStructure.PermissionName); }); - - foreach (var level1Permission in Permission.PermissionsStructure.ChildPermissions) - { - //Add 1 level deep nested level policy and Claims - o.AddPolicy(level1Permission.PermissionName, configure => - { - configure.RequireClaim(Permission.PermissionsStructure.PermissionName, Permission.PermissionsStructure.PermissionName); - configure.RequireClaim(level1Permission.PermissionName, level1Permission.PermissionName); - }); - - //Add 2 levels deep policy and Claims - foreach (var level2Permission in level1Permission.ChildPermissions) - { - o.AddPolicy(level2Permission.PermissionName, configure => - { - configure.RequireClaim(Permission.PermissionsStructure.PermissionName, Permission.PermissionsStructure.PermissionName); - configure.RequireClaim(level1Permission.PermissionName, level1Permission.PermissionName); - configure.RequireClaim(level2Permission.PermissionName, level2Permission.PermissionName); - }); - } - } - } - }); - - // Return the service collection - return services; - } - - /// <summary> - /// Uses the Piranha Manager. - /// </summary> - /// <param name="builder">The application builder</param> - /// <returns>The builder</returns> - public static IApplicationBuilder UsePiranhaManager(this IApplicationBuilder builder) { - return builder.UseStaticFiles(new StaticFileOptions - { - FileProvider = new EmbeddedFileProvider(typeof(ManagerModuleExtensions).Assembly, "Piranha.Manager.assets.dist"), - RequestPath = "/manager/assets" - }); - } - - /// <summary> - /// Adds the mappings needed for the Piranha Manager to - /// the endpoint routes. - /// </summary> - /// <param name="builder">The route builder</param> - public static void MapPiranhaManager(this IEndpointRouteBuilder builder) - { - builder.MapHub<PreviewHub>("/manager/preview"); - builder.MapRazorPages(); - } - - public static IMvcBuilder AddPiranhaManagerOptions(this IMvcBuilder builder, - Action<MvcNewtonsoftJsonOptions> jsonOptions = null) - { - return builder - .AddRazorPagesOptions(options => - { - options.Conventions.AuthorizeAreaFolder("Manager", "/"); - }) - .AddViewLocalization() - .AddDataAnnotationsLocalization() - .AddNewtonsoftJson(options => - { - // Invoke custom json options - jsonOptions?.Invoke(options); - - // Set required options for Piranha - options.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto; - }); - } - - /// <summary> - /// Static accessor to Manager module if it is registered in the Piranha - /// application. - /// </summary> - /// <param name="modules">The available modules</param> - /// <returns>The manager module</returns> - public static Piranha.Manager.Module Manager(this Piranha.Runtime.AppModuleList modules) - { - return modules.Get<Piranha.Manager.Module>(); - } -} +/* + * Copyright (c) .NET Foundation and Contributors + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + * https://github.com/piranhacms/piranha.core + * + */ + +using System; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Newtonsoft.Json; +using Piranha.Manager; +using Piranha.Manager.Hubs; +using Piranha.Manager.Services; + +public static class ManagerModuleExtensions +{ + /// <summary> + /// Adds the Piranha manager module. + /// </summary> + /// <param name="services">The current service collection</param> + /// <returns>The services</returns> + public static IServiceCollection AddPiranhaManager(this IServiceCollection services) + { + return services.AddPiranhaManager(null); + } + + /// <summary> + /// Adds the Piranha manager module. + /// </summary> + /// <param name="services">The current service collection</param> + /// <param name="configurePolicy">The delegate that will be used to build the Piranha Manager named policies.</param> + /// <returns>The services</returns> + public static IServiceCollection AddPiranhaManager(this IServiceCollection services, Action<string, AuthorizationPolicyBuilder> configurePolicy) + { + // Add the manager module + Piranha.App.Modules.Register<Piranha.Manager.Module>(); + + // Add the manager services + services.AddScoped<AliasService>(); + services.AddScoped<CommentService>(); + services.AddScoped<ConfigService>(); + services.AddScoped<ContentService>(); + services.AddScoped<ContentTypeService>(); + services.AddScoped<LanguageService>(); + services.AddScoped<MediaService>(); + services.AddScoped<ModuleService>(); + services.AddScoped<PageService>(); + services.AddScoped<PostService>(); + services.AddScoped<SiteService>(); + + // Add localization service + services.AddScoped<ManagerLocalizer>(); + + // Add session support + services.AddSession(); + + // Add SignalR + services.AddSignalR(); + + // Setup authorization policies + services.AddAuthorization(o => + { + if (configurePolicy is not null) + { + //If custom AuthorizationOptions delegate is provided, invoke + foreach (var permission in Permission.All()) + { + o.AddPolicy(permission, configure => configurePolicy.Invoke(permission, configure)); + } + } + else + { + //Else configure default Claims based Policies, using Piranha nested permissions structure + //Add root (Admin) policy and Claims + o.AddPolicy(Permission.PermissionsStructure.PermissionName, configure => { configure.RequireClaim(Permission.PermissionsStructure.PermissionName, Permission.PermissionsStructure.PermissionName); }); + + foreach (var level1Permission in Permission.PermissionsStructure.ChildPermissions) + { + //Add 1 level deep nested level policy and Claims + o.AddPolicy(level1Permission.PermissionName, configure => + { + configure.RequireClaim(Permission.PermissionsStructure.PermissionName, Permission.PermissionsStructure.PermissionName); + configure.RequireClaim(level1Permission.PermissionName, level1Permission.PermissionName); + }); + + //Add 2 levels deep policy and Claims + foreach (var level2Permission in level1Permission.ChildPermissions) + { + o.AddPolicy(level2Permission.PermissionName, configure => + { + configure.RequireClaim(Permission.PermissionsStructure.PermissionName, Permission.PermissionsStructure.PermissionName); + configure.RequireClaim(level1Permission.PermissionName, level1Permission.PermissionName); + configure.RequireClaim(level2Permission.PermissionName, level2Permission.PermissionName); + }); + } + } + } + }); + + // Return the service collection + return services; + } + + /// <summary> + /// Uses the Piranha Manager. + /// </summary> + /// <param name="builder">The application builder</param> + /// <returns>The builder</returns> + public static IApplicationBuilder UsePiranhaManager(this IApplicationBuilder builder) { + return builder.UseStaticFiles(new StaticFileOptions + { + FileProvider = new EmbeddedFileProvider(typeof(ManagerModuleExtensions).Assembly, "Piranha.Manager.assets.dist"), + RequestPath = "/manager/assets" + }); + } + + /// <summary> + /// Adds the mappings needed for the Piranha Manager to + /// the endpoint routes. + /// </summary> + /// <param name="builder">The route builder</param> + public static void MapPiranhaManager(this IEndpointRouteBuilder builder) + { + builder.MapHub<PreviewHub>("/manager/preview"); + builder.MapRazorPages(); + } + + public static IMvcBuilder AddPiranhaManagerOptions(this IMvcBuilder builder, + Action<MvcNewtonsoftJsonOptions> jsonOptions = null) + { + return builder + .AddRazorPagesOptions(options => + { + options.Conventions.AuthorizeAreaFolder("Manager", "/"); + }) + .AddViewLocalization() + .AddDataAnnotationsLocalization() + .AddNewtonsoftJson(options => + { + // Invoke custom json options + jsonOptions?.Invoke(options); + + // Set required options for Piranha + options.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto; + }); + } + + /// <summary> + /// Static accessor to Manager module if it is registered in the Piranha + /// application. + /// </summary> + /// <param name="modules">The available modules</param> + /// <returns>The manager module</returns> + public static Piranha.Manager.Module Manager(this Piranha.Runtime.AppModuleList modules) + { + return modules.Get<Piranha.Manager.Module>(); + } +}
core/Piranha.Manager/Extensions/ManagerStartupExtensions.cs+23 −6 renamed@@ -22,22 +22,39 @@ public static class ManagerStartupExtensions /// Uses the Piranha Manager services if simple startup is used. /// </summary> /// <param name="serviceBuilder">The service builder</param> + /// <param name="options">The optional options</param> /// <param name="jsonOptions">Optional JSON options</param> /// <returns>The updated builder</returns> public static PiranhaServiceBuilder UseManager(this PiranhaServiceBuilder serviceBuilder, + Action<ManagerOptions> options = null, Action<MvcNewtonsoftJsonOptions> jsonOptions = null) { - // Add dependent services - serviceBuilder.Services.AddLocalization(options => - options.ResourcesPath = "Resources" + // Perform optional configuration + var managerOptions = new ManagerOptions(); + options?.Invoke(managerOptions); + + // Add manager services + serviceBuilder.Services.AddPiranhaManager(); + + // Add dependent ASP.NET services + serviceBuilder.Services.AddLocalization(o => + o.ResourcesPath = "Resources" ); serviceBuilder.Services.AddControllersWithViews(); serviceBuilder.Services.AddRazorPages() .AddPiranhaManagerOptions(jsonOptions); + serviceBuilder.Services.AddAntiforgery(o => + { + o.HeaderName = managerOptions.XsrfHeaderName; + }); - // Add manager services - serviceBuilder.Services.AddPiranhaManager(); - + // Add options + serviceBuilder.Services.Configure<ManagerOptions>(o => + { + o.JsonOptions = managerOptions.JsonOptions; + o.XsrfCookieName = managerOptions.XsrfCookieName; + o.XsrfHeaderName = managerOptions.XsrfHeaderName; + }); return serviceBuilder; }
core/Piranha.Manager.LocalAuth/Areas/Manager/Pages/Login.cshtml.cs+2 −3 modified@@ -104,10 +104,9 @@ public async Task<IActionResult> OnPostAsync(string returnUrl = null) if (!string.IsNullOrEmpty(returnUrl)) { - return LocalRedirect(returnUrl); + return LocalRedirect($"~/manager/login/auth?returnUrl={ returnUrl }"); } - - return new RedirectToPageResult("Index"); + return LocalRedirect("~/manager/login/auth"); } } } \ No newline at end of file
core/Piranha.Manager/ManagerOptions.cs+36 −0 added@@ -0,0 +1,36 @@ +/* + * Copyright (c) .NET Foundation and Contributors + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + * https://github.com/piranhacms/piranha.core + * + */ + +using System; +using Microsoft.AspNetCore.Mvc; + +namespace Piranha.Manager +{ + public sealed class ManagerOptions + { + /// <summary> + /// Gets/sets the XSRF cookie name that will be set by the manager after + /// successful authentication. The default is "XSRF-REQUEST-TOKEN". + /// </summary> + public string XsrfCookieName { get; set; } = "XSRF-REQUEST-TOKEN"; + + /// <summary> + /// Gets/sets the name of the header the manager will use to send back the + /// anti forgery information to the API. The default is "X-XSRF-TOKEN". + /// </summary> + public string XsrfHeaderName { get; set; } = "X-XSRF-TOKEN"; + + /// <summary> + /// Gets/sets the optional JSON options for the Newtonsoft serializer. + /// </summary> + /// <value></value> + public Action<MvcNewtonsoftJsonOptions> JsonOptions { get; set; } + } +} \ No newline at end of file
core/Piranha.Manager/Models/LanguageEditModel.cs+5 −0 modified@@ -22,5 +22,10 @@ public class LanguageEditModel /// Gets/sets the available languages /// </summary> public IEnumerable<Language> Items { get; set; } = new List<Language>(); + + /// <summary> + /// Gets/sets the optional status message from the last operation. + /// </summary> + public StatusMessage Status { get; set; } } } \ No newline at end of file
identity/Piranha.AspNetCore.Identity/Areas/Manager/Views/Role/List.cshtml+6 −3 modified@@ -53,9 +53,12 @@ <td class="actions one"> @if ((await Auth.AuthorizeAsync(User, Piranha.AspNetCore.Identity.Permissions.RolesDelete)).Succeeded) { - <a class="danger" href="@Url.Action("Delete", new {id = role.Id})"> - <span class="fas fa-trash"></span> - </a> + <form method="post" action="~/manager/role/delete"> + <input type="hidden" name="id" value="@role.Id"> + <button class="danger"> + <span class="fas fa-trash"></span> + </button> + </form> } </td> </tr>
identity/Piranha.AspNetCore.Identity/assets/piranha.useredit.js+2 −6 modified@@ -48,9 +48,7 @@ piranha.useredit= new Vue({ console.log(JSON.stringify(self.userModel)); fetch(piranha.baseUrl + "manager/user/save", { method: "post", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(self.userModel) }) .then(function (response) { @@ -102,9 +100,7 @@ piranha.useredit= new Vue({ var ok = false; fetch(piranha.baseUrl + "manager/user/delete", { method: "delete", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(userId) }) .then(function (response) {
identity/Piranha.AspNetCore.Identity/assets/piranha.userlist.js+1 −3 modified@@ -50,9 +50,7 @@ piranha.userlist = new Vue({ onConfirm: function () { fetch(piranha.baseUrl + "manager/user/delete", { method: "delete", - headers: { - "Content-Type": "application/json" - }, + headers: piranha.utils.antiForgeryHeaders(), body: JSON.stringify(user.id) }) .then(function (response) { return response.json(); })
identity/Piranha.AspNetCore.Identity/Controllers/RoleController.cs+2 −1 modified@@ -18,6 +18,7 @@ namespace Piranha.AspNetCore.Identity.Controllers { [Area("Manager")] + [AutoValidateAntiforgeryToken] public class RoleController : ManagerController { private readonly IDb _db; @@ -66,7 +67,7 @@ public IActionResult Save(RoleEditModel model) return View("Edit", model); } - [HttpGet] + [HttpPost] [Route("/manager/role/delete")] [Authorize(Policy = Permissions.RolesDelete)] public IActionResult Delete(Guid id)
identity/Piranha.AspNetCore.Identity/Controllers/UserController.cs+1 −0 modified@@ -28,6 +28,7 @@ namespace Piranha.AspNetCore.Identity.Controllers /// Manager controller for managing users accounts. /// </summary> [Area("Manager")] + [AutoValidateAntiforgeryToken] public class UserController : ManagerController { private readonly IDb _db;
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-ppq7-88c7-q879ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-25976ghsaADVISORY
- github.com/PiranhaCMS/piranha.core/commit/e42abacdd0dd880ce9cf6607efcc24646ac82edaghsax_refsource_MISCWEB
- www.whitesourcesoftware.com/vulnerability-database/CVE-2021-25976ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.