Skip to content

Instantly share code, notes, and snippets.

@davidknipe
Last active April 14, 2016 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidknipe/e1bfad17aab181fbf493 to your computer and use it in GitHub Desktop.
Save davidknipe/e1bfad17aab181fbf493 to your computer and use it in GitHub Desktop.
Approval for moving content in Episerver page tree
using System;
using System.Linq;
using Epi9Site.PageMoveApproval.Models;
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Framework.Localization;
using EPiServer.Security;
using EPiServer.ServiceLocation;
namespace Epi9Site.PageMoveApproval.Init
{
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class CaptureRequestsInit : IInitializableModule
{
private static bool _enableCheck;
private static readonly object _lockObject = new Object();
public void Initialize(InitializationEngine context)
{
IContentEvents events = ServiceLocator.Current.GetInstance<IContentEvents>();
events.MovingContent += MovingContent;
events.PublishedContent += PublishedContent;
_enableCheck = true;
}
private void MovingContent(object sender, EPiServer.ContentEventArgs e)
{
lock (_lockObject)
{
if (_enableCheck == false)
return;
}
// We only want to operate on pages but this can be extended for any page type we like
if (!(e.Content is PageData)
|| (e.Content is PageMoveRequestsRoot)
|| (e.Content is PageMoveRequest)
)
return;
var repo = ServiceLocator.Current.GetInstance<IContentRepository>();
if (repo == null) return;
// Check if there is an outstanding request
PageMoveRequest moveRequest = null;
bool requestExists = false;
//var allPages = repo.GetItems(repo.GetDescendents(GetPageMoveRequestRoot(repo)).ToList());
// .GetChildren<PageData>();
var existingRequests = repo
.GetChildren<PageMoveRequest>(GetPageMoveRequestRoot(repo), LanguageSelector.AutoDetect(true));
foreach (var existingRequest in existingRequests)
{
if (existingRequest.SourceContentReference == e.ContentLink)
{
// Update the existing request
moveRequest = existingRequest.CreateWritableClone() as PageMoveRequest;
requestExists = true;
break;
}
}
if (moveRequest == null)
{
// Set up a new page move request
moveRequest = repo.GetDefault<PageMoveRequest>(GetPageMoveRequestRoot(repo));
moveRequest.PageName = "Move request for [" + repo.Get<IContent>(e.ContentLink).Name + "]";
moveRequest.URLSegment = EPiServer.Web.UrlSegment.CreateUrlSegment(moveRequest);
}
moveRequest.SourceContentReference = e.ContentLink;
moveRequest.TargetLocationContentReference = e.TargetLink;
repo.Save(moveRequest, SaveAction.Save, AccessLevel.NoAccess);
// Get the translated error message
var lang = ServiceLocator.Current.GetInstance<LocalizationService>();
string errorMessage;
if (requestExists)
{
if (!lang.TryGetString("/errors/existingpagemoveneedsapproval", out errorMessage))
{
errorMessage =
"This request to move a page needs approval and an existing request has been updated. If you have the correct access level approval requests can be seen in the \"Page Move Requests\" below the root folder in the site";
}
}
else
{
if (!lang.TryGetString("/errors/pagemoveneedsapproval", out errorMessage))
{
errorMessage =
"This request to move a page needs approval, please wait while a publisher approves your request. If you have the correct access level approval requests can be seen in the \"Page Move Requests\" below the root folder in the site";
}
}
// Set up the error
e.CancelAction = true;
e.CancelReason = errorMessage;
}
private void PublishedContent(object sender, ContentEventArgs e)
{
// Only act on page move requests
if (!(e.Content is PageMoveRequest)) return;
var repo = ServiceLocator.Current.GetInstance<IContentRepository>();
if (repo == null) return;
var sourceRequest = (e.Content as PageMoveRequest);
lock (_lockObject)
{
// Need to disable the move check from executing at this point
_enableCheck = false;
repo.Move(sourceRequest.SourceContentReference, sourceRequest.TargetLocationContentReference,
AccessLevel.NoAccess, AccessLevel.NoAccess);
// Delete the original request by moving it to the recyle bin
repo.Move(
e.Content.ContentLink,
ContentReference.WasteBasket,
AccessLevel.NoAccess, AccessLevel.NoAccess);
//var pageMoveRequest = (e.Content as PageMoveRequest).CreateWritableClone();
_enableCheck = true;
}
}
public void Uninitialize(InitializationEngine context)
{
IContentEvents events = ServiceLocator.Current.GetInstance<IContentEvents>();
events.MovingContent -= MovingContent;
}
private ContentReference GetPageMoveRequestRoot(IContentRepository repo)
{
// May generate an exception so should be a property
var rootPage = repo.GetChildren<PageMoveRequestsRoot>(ContentReference.RootPage);
if (rootPage.Any())
{
return rootPage.First().ContentLink;
}
else
{
throw new Exception("Could not find instance of PageMoveRequestsRoot. This should be automatically created by an initialization module. Restarting your site may solve this issue.");
}
}
}
}
@model Epi9Site.PageMoveApproval.Models.ViewModels.PageMoveRequestViewModel
@using EPiServer.Framework.Web.Resources
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</head>
<body>
<h1>Page move request</h1>
@*<div class="alert alert-info" role="alert">
An editor has requested a page move. Please review this request below
</div>*@
<div class="well">
<h2>Source content</h2>
<h4>
<span class="glyphicon glyphicon-arrow-right"></span>
@Model.Source
</h4>
</div>
<div class="well">
<h2>Target location</h2>
<h4>
<span class="glyphicon glyphicon-share-alt"></span>
@Model.Target
</h4>
</div>
@if (Model.AvailableForAction)
{
<div class="alert alert-warning" role="alert">
<h3>
<strong><span class="glyphicon glyphicon-exclamation-sign"></span>Action required</strong> Click publish to approve this change or delete this page to cancel the request
</h3>
</div>
}
else if (Model.WasApproved)
{
<div class="alert alert-success" role="alert">
<h3>
<strong><span class="glyphicon glyphicon-ok"></span></strong> The page has now been moved in the tree. You may need to refresh the tree to see the effect.
</h3>
</div>
}
else
{
<div class="alert alert-danger" role="alert">
<h3>
<strong><span class="glyphicon glyphicon-remove"></span></strong> This move was not approved
</h3>
</div>
}
</body>
</html>
<module>
<clientResources>
<add name="epi-cms.widgets.base" path="Scripts/widget/ContentTreeModelConfirmation.js" resourceType="Script" />
</clientResources>
<dojo>
<packages>
<add name="customised-move" location="Scripts/widget" />
</packages>
<aliases>
<add from="epi-cms/widget/ContentTreeModelConfirmation" to="customised-move/ContentTreeModelConfirmation" />
</aliases>
</dojo>
</module>
using System;
using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using EPiServer.SpecializedProperties;
namespace Epi9Site.PageMoveApproval.Models
{
[ContentType(
DisplayName = "Page Move Request"
, GUID = "d9ed8365-d08d-424c-a60f-b8c3d098ec14"
, AvailableInEditMode = false
, Description = "Used to approve page moves it the tree")]
[AvailableContentTypes(Include = new Type[] { })]
public class PageMoveRequest : PageData
{
[Display(
Name = "Move Source",
Description = "The item to be moved",
GroupName = "Move parameters",
Order = 2)]
public virtual ContentReference SourceContentReference { get; set; }
[Display(
Name = "Move Target",
Description = "The location where the content will be moved to",
GroupName = "Move parameters",
Order = 2)]
public virtual ContentReference TargetLocationContentReference { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Epi9Site.PageMoveApproval.Models;
using Epi9Site.PageMoveApproval.Models.ViewModels;
using EPiServer;
using EPiServer.Core;
using EPiServer.Framework.Web.Resources;
using EPiServer.ServiceLocation;
using EPiServer.Web.Mvc;
namespace Epi9Site.PageMoveApproval.Controllers
{
public class PageMoveRequestController : PageController<PageMoveRequest>
{
private IContentLoader _contentLoader { get; set; }
public PageMoveRequestController(IContentLoader contentLoader)
{
_contentLoader = contentLoader;
}
public ViewResult Index(PageMoveRequest currentPage)
{
var res = ServiceLocator.Current.GetInstance<IClientResourceService>();
var model = new PageMoveRequestViewModel
{
CurrentPage = currentPage,
Source = GetParentList(currentPage.SourceContentReference),
Target = GetParentList(currentPage.TargetLocationContentReference),
AvailableForAction = !currentPage.IsDeleted,
WasApproved = PublishedStateAssessor.IsPublished(currentPage, PublishedStateCondition.IgnoreDeleted)
};
return View("~/PageMoveApproval/Views/PageMoveRequest/Index.cshtml", model);
}
private string GetParentList(ContentReference contentReference)
{
var content = _contentLoader.Get<IContent>(contentReference);
var structure = new List<string>();
GetAllParents(content, structure);
structure.Reverse();
var itemStructure = String.Join(" > ", structure);
return itemStructure;
}
private void GetAllParents(IContent currentContent, List<string> contentStructure)
{
contentStructure.Add(currentContent.Name);
if (currentContent.ParentLink != null && currentContent.ParentLink != ContentReference.EmptyReference)
{
GetAllParents(_contentLoader.Get<IContent>(currentContent.ParentLink), contentStructure);
}
}
}
}
using System;
using Epi9Site.Models.Pages;
using EPiServer.Core;
using EPiServer.DataAnnotations;
using EPiServer.UI.Admin;
namespace Epi9Site.PageMoveApproval.Models
{
[ContentType(DisplayName = "Page Move Requests"
, AvailableInEditMode = false
, GUID = "9C8C987F-FDD6-4749-8EE4-66A081CBFA6B"
, Description = "Used to list all page move requests")]
[AvailableContentTypes(Include = new Type[] { })]
public class PageMoveRequestsRoot : PageData
{
}
}
using System.Linq;
using Epi9Site.PageMoveApproval.Models;
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Security;
using EPiServer.ServiceLocation;
namespace Epi9Site.PageMoveApproval.Init
{
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class PageMoveRequestsRootInit : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
this.EnsureRootExists();
}
private bool EnsureRootExists()
{
if (!RootExists())
{
var repo = ServiceLocator.Current.GetInstance<IContentRepository>();
var root = repo.GetDefault<PageMoveRequestsRoot>(ContentReference.RootPage);
root.URLSegment = EPiServer.Web.UrlSegment.CreateUrlSegment(root);
root.Name = "Page move requests";
repo.Save(root, SaveAction.Publish, AccessLevel.NoAccess);
return true;
}
return false;
}
private bool RootExists()
{
var contentRepo = ServiceLocator.Current.GetInstance<IContentRepository>();
var ruleRepoPage = contentRepo.GetChildren<PageMoveRequestsRoot>(ContentReference.RootPage);
if (ruleRepoPage.Any())
{
return true;
}
return false;
}
public void Uninitialize(InitializationEngine context) { }
}
}
using Epi9Site.PageMoveApproval.Models;
using EPiServer.Shell;
namespace Epi9Site.PageMoveApproval.UIDescriptor
{
[UIDescriptorRegistration]
public class PageMoveRequestsRootUiDescriptor : UIDescriptor<PageMoveRequestsRoot>
{
public PageMoveRequestsRootUiDescriptor()
: base("epi-iconObjectRoot")
{
}
}
}
using Epi9Site.PageMoveApproval.Models;
using EPiServer.Shell;
namespace Epi9Site.PageMoveApproval.UIDescriptor
{
[UIDescriptorRegistration]
public class PageMoveRequestUiDescriptor : UIDescriptor<PageMoveRequest>
{
public PageMoveRequestUiDescriptor()
: base("epi-iconRight")
{
}
}
}
namespace Epi9Site.PageMoveApproval.Models.ViewModels
{
public class PageMoveRequestViewModel
{
public PageMoveRequest CurrentPage { get; set; }
public string Source;
public string Target;
public bool AvailableForAction { get; set; }
public bool WasApproved;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment