2012-11-07 13:56:52 -01:00
using System ;
2012-10-03 12:51:32 -02:00
using System.Collections.Generic ;
using System.Linq ;
2012-11-12 08:39:29 -01:00
using System.Web ;
2012-12-14 15:19:54 -01:00
using System.Xml.Linq ;
2012-12-10 10:57:51 -01:00
using Umbraco.Core.Auditing ;
2012-12-15 10:43:03 +05:00
using Umbraco.Core.Events ;
2012-12-14 15:19:54 -01:00
using Umbraco.Core.IO ;
2012-10-29 14:28:16 -01:00
using Umbraco.Core.Logging ;
2012-10-03 12:51:32 -02:00
using Umbraco.Core.Models ;
2012-10-31 15:15:02 -01:00
using Umbraco.Core.Models.EntityBase ;
2012-12-14 15:19:54 -01:00
using Umbraco.Core.Models.Rdbms ;
2012-10-03 12:51:32 -02:00
using Umbraco.Core.Persistence ;
2012-10-10 12:13:23 -02:00
using Umbraco.Core.Persistence.Querying ;
using Umbraco.Core.Persistence.UnitOfWork ;
2012-11-06 10:47:14 -01:00
using Umbraco.Core.Publishing ;
2012-10-03 12:51:32 -02:00
2012-11-12 07:40:11 -01:00
namespace Umbraco.Core.Services
2012-10-03 12:51:32 -02:00
{
2012-12-11 23:19:07 +05:00
/// <summary>
/// Represents the Content Service, which is an easy access to operations involving <see cref="IContent"/>
/// </summary>
public class ContentService : IContentService
{
2012-12-11 12:03:36 +05:00
private readonly IDatabaseUnitOfWorkProvider _uowProvider ;
2012-12-11 23:19:07 +05:00
private readonly IPublishingStrategy _publishingStrategy ;
2012-12-11 12:03:36 +05:00
private readonly IUserService _userService ;
2012-12-12 10:47:14 -01:00
private readonly RepositoryFactory _repositoryFactory ;
2012-12-11 23:19:07 +05:00
private HttpContextBase _httpContext ;
2012-12-14 13:27:10 -01:00
public ContentService ( )
: this ( new RepositoryFactory ( ) )
{ }
2012-12-14 12:33:14 -01:00
public ContentService ( RepositoryFactory repositoryFactory )
: this ( new PetaPocoUnitOfWorkProvider ( ) , repositoryFactory , new PublishingStrategy ( ) )
2012-12-12 09:00:00 -01:00
{ }
2012-12-14 13:27:10 -01:00
public ContentService ( IDatabaseUnitOfWorkProvider provider )
: this ( provider , new RepositoryFactory ( ) , new PublishingStrategy ( ) )
{ }
2012-12-14 12:33:14 -01:00
public ContentService ( IDatabaseUnitOfWorkProvider provider , RepositoryFactory repositoryFactory )
: this ( provider , repositoryFactory , new PublishingStrategy ( ) )
{ }
internal ContentService ( IDatabaseUnitOfWorkProvider provider , RepositoryFactory repositoryFactory , IPublishingStrategy publishingStrategy )
2012-12-11 23:19:07 +05:00
{
_uowProvider = provider ;
_publishingStrategy = publishingStrategy ;
2012-12-12 10:47:14 -01:00
_repositoryFactory = repositoryFactory ;
2012-12-11 23:19:07 +05:00
}
2012-10-10 12:13:23 -02:00
2012-12-14 12:33:14 -01:00
internal ContentService ( IDatabaseUnitOfWorkProvider provider , RepositoryFactory repositoryFactory , IPublishingStrategy publishingStrategy , IUserService userService )
2012-12-11 23:19:07 +05:00
{
2012-12-12 10:47:14 -01:00
_uowProvider = provider ;
2012-12-11 23:19:07 +05:00
_publishingStrategy = publishingStrategy ;
_userService = userService ;
2012-12-12 10:47:14 -01:00
_repositoryFactory = repositoryFactory ;
2012-12-11 23:19:07 +05:00
}
/// <summary>
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
/// that this Content is based on.
/// </summary>
/// <param name="parentId">Id of Parent for the new Content</param>
/// <param name="contentTypeAlias">Alias of the <see cref="IContentType"/></param>
/// <param name="userId">Optional id of the user creating the content</param>
/// <returns><see cref="IContent"/></returns>
public IContent CreateContent ( int parentId , string contentTypeAlias , int userId = - 1 )
{
2012-12-15 11:04:03 -01:00
IContentType contentType = null ;
IContent content = null ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentTypeRepository ( uow ) )
{
var query = Query < IContentType > . Builder . Where ( x = > x . Alias = = contentTypeAlias ) ;
var contentTypes = repository . GetByQuery ( query ) ;
if ( ! contentTypes . Any ( ) )
throw new Exception ( string . Format ( "No ContentType matching the passed in Alias: '{0}' was found" ,
contentTypeAlias ) ) ;
contentType = contentTypes . First ( ) ;
if ( contentType = = null )
throw new Exception ( string . Format ( "ContentType matching the passed in Alias: '{0}' was null" ,
contentTypeAlias ) ) ;
}
var e = new NewEventArgs { Alias = contentTypeAlias , ParentId = parentId } ;
if ( Creating ! = null )
Creating ( content , e ) ;
if ( ! e . Cancel )
{
content = new Content ( parentId , contentType ) ;
SetUser ( content , userId ) ;
SetWriter ( content , userId ) ;
if ( Created ! = null )
Created ( content , e ) ;
Audit . Add ( AuditTypes . New , "" , content . CreatorId , content . Id ) ;
}
return content ;
2012-12-11 23:19:07 +05:00
}
/// <summary>
/// Gets an <see cref="IContent"/> object by Id
/// </summary>
/// <param name="id">Id of the Content to retrieve</param>
/// <returns><see cref="IContent"/></returns>
public IContent GetById ( int id )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
return repository . Get ( id ) ;
}
}
/// <summary>
/// Gets an <see cref="IContent"/> object by its 'UniqueId'
/// </summary>
/// <param name="key">Guid key of the Content to retrieve</param>
/// <returns><see cref="IContent"/></returns>
public IContent GetById ( Guid key )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . Key = = key ) ;
var contents = repository . GetByQuery ( query ) ;
2012-12-11 23:19:07 +05:00
return contents . SingleOrDefault ( ) ;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by the Id of the <see cref="IContentType"/>
/// </summary>
/// <param name="id">Id of the <see cref="IContentType"/></param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetContentOfContentType ( int id )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . ContentTypeId = = id ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-24 08:36:45 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Level
/// </summary>
/// <param name="level">The level to retrieve Content from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetByLevel ( int level )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . Level = = level ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-10 12:13:23 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetChildren ( int id )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . ParentId = = id ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-10 12:13:23 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
2012-12-14 15:19:54 -01:00
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by its name or partial name
/// </summary>
/// <param name="parentId">Id of the Parent to retrieve Children from</param>
/// <param name="name">Full or partial name of the children</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetChildrenByName ( int parentId , string name )
{
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
{
var query = Query < IContent > . Builder . Where ( x = > x . ParentId = = parentId & & x . Name . Contains ( name ) ) ;
var contents = repository . GetByQuery ( query ) ;
return contents ;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetDescendants ( int id )
{
var content = GetById ( id ) ;
return GetDescendants ( content ) ;
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="content"><see cref="IContent"/> item to retrieve Descendants from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetDescendants ( IContent content )
{
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
{
var query = Query < IContent > . Builder . Where ( x = > x . Path . StartsWith ( content . Path ) ) ;
var contents = repository . GetByQuery ( query ) ;
return contents ;
}
}
/// <summary>
/// Gets a specific version of an <see cref="IContent"/> item.
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/> to retrieve version from</param>
/// <param name="versionId">Id of the version to retrieve</param>
/// <returns>An <see cref="IContent"/> item</returns>
public IContent GetByIdVersion ( int id , Guid versionId )
{
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
{
return repository . GetByVersion ( id , versionId ) ;
}
}
2012-12-11 23:19:07 +05:00
/// <summary>
/// Gets a collection of an <see cref="IContent"/> objects versions by Id
/// </summary>
/// <param name="id"></param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetVersions ( int id )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var versions = repository . GetAllVersions ( id ) ;
2012-12-11 23:19:07 +05:00
return versions ;
}
}
2012-12-14 15:19:54 -01:00
/// <summary>
/// Gets the published version of an <see cref="IContent"/> item
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/> to retrieve version from</param>
/// <returns>An <see cref="IContent"/> item</returns>
public IContent GetPublishedVersion ( int id )
{
2012-12-15 11:04:03 -01:00
var version = GetVersions ( id ) ;
return version . FirstOrDefault ( x = > x . Published = = true ) ;
2012-12-14 15:19:54 -01:00
}
2012-12-11 23:19:07 +05:00
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects, which reside at the first level / root
/// </summary>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetRootContent ( )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . ParentId = = - 1 ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-10 12:13:23 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects, which has an expiration date less than or equal to today.
/// </summary>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetContentForExpiration ( )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . Published = = true & & x . ExpireDate < = DateTime . UtcNow ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-10 12:13:23 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects, which has a release date less than or equal to today.
/// </summary>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetContentForRelease ( )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . Published = = false & & x . ReleaseDate < = DateTime . UtcNow ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-10 12:13:23 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
/// <summary>
/// Gets a collection of an <see cref="IContent"/> objects, which resides in the Recycle Bin
/// </summary>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable < IContent > GetContentInRecycleBin ( )
{
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . ParentId = = - 20 ) ;
var contents = repository . GetByQuery ( query ) ;
2012-10-10 12:13:23 -02:00
2012-12-11 23:19:07 +05:00
return contents ;
}
}
2012-12-14 15:19:54 -01:00
/// <summary>
/// Checks whether an <see cref="IContent"/> item has any children
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/></param>
/// <returns>True if the content has any children otherwise False</returns>
public bool HasChildren ( int id )
{
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
{
var query = Query < IContent > . Builder . Where ( x = > x . ParentId = = id ) ;
int count = repository . Count ( query ) ;
return count > 0 ;
}
}
/// <summary>
/// Checks whether an <see cref="IContent"/> item has any published versions
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/></param>
/// <returns>True if the content has any published version otherwise False</returns>
public bool HasPublishedVersion ( int id )
{
using ( var repository = _repositoryFactory . CreateContentRepository ( _uowProvider . GetUnitOfWork ( ) ) )
{
var query = Query < IContent > . Builder . Where ( x = > x . Published = = true & & x . Id = = id ) ;
int count = repository . Count ( query ) ;
return count > 0 ;
}
}
2012-12-15 11:04:03 -01:00
/// <summary>
/// Re-Publishes all Content
/// </summary>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool RePublishAll ( int userId = - 1 , bool omitCacheRefresh = false )
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
var list = new List < IContent > ( ) ;
var updated = new List < IContent > ( ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
var rootContent = GetRootContent ( ) ;
foreach ( var content in rootContent )
{
if ( content . IsValid ( ) )
{
list . Add ( content ) ;
list . AddRange ( GetChildrenDeep ( content . Id ) ) ;
}
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Publish and then update the database with new status
var published = _publishingStrategy . PublishWithChildren ( list , userId ) ;
if ( published )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
//Only loop through content where the Published property has been updated
foreach ( var item in list . Where ( x = > ( ( ICanBeDirty ) x ) . IsPropertyDirty ( "Published" ) ) )
{
SetWriter ( item , userId ) ;
repository . AddOrUpdate ( item ) ;
updated . Add ( item ) ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
uow . Commit ( ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
foreach ( var c in updated )
{
var xml = c . ToXml ( ) ;
var poco = new ContentXmlDto { NodeId = c . Id , Xml = xml . ToString ( SaveOptions . None ) } ;
var exists = uow . Database . FirstOrDefault < ContentXmlDto > ( "WHERE nodeId = @Id" , new { Id = c . Id } ) ! =
null ;
int result = exists
? uow . Database . Update ( poco )
: Convert . ToInt32 ( uow . Database . Insert ( poco ) ) ;
}
}
//Updating content to published state is finished, so we fire event through PublishingStrategy to have cache updated
if ( omitCacheRefresh = = false )
_publishingStrategy . PublishingFinalized ( updated , true ) ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Publish , "RePublish All performed by user" , userId = = - 1 ? 0 : userId , - 1 ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
return published ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
2012-12-14 15:19:54 -01:00
/// Publishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool Publish ( IContent content , int userId = - 1 , bool omitCacheRefresh = false )
{
2012-12-15 11:04:03 -01:00
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
2012-12-14 15:19:54 -01:00
return SaveAndPublish ( content , userId , omitCacheRefresh ) ;
}
2012-12-15 11:04:03 -01:00
/// <summary>
/// Publishes a <see cref="IContent"/> object and all its children
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool PublishWithChildren ( IContent content , int userId = - 1 , bool omitCacheRefresh = false )
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
if ( content . ParentId ! = - 1 & & content . ParentId ! = - 20 & & HasPublishedVersion ( content . ParentId ) = = false )
{
LogHelper . Info < ContentService > (
string . Format (
"Content '{0}' with Id '{1}' could not be published because its parent is not published." ,
content . Name , content . Id ) ) ;
return false ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Content contains invalid property values and can therefore not be published - fire event?
if ( ! content . IsValid ( ) )
{
LogHelper . Info < ContentService > (
string . Format ( "Content '{0}' with Id '{1}' could not be published because of invalid properties." ,
content . Name , content . Id ) ) ;
return false ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path));
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
var updated = new List < IContent > ( ) ;
var list = new List < IContent > ( ) ;
list . Add ( content ) ;
list . AddRange ( GetChildrenDeep ( content . Id ) ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Publish and then update the database with new status
var published = _publishingStrategy . PublishWithChildren ( list , userId ) ;
if ( published )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
//Only loop through content where the Published property has been updated
foreach ( var item in list . Where ( x = > ( ( ICanBeDirty ) x ) . IsPropertyDirty ( "Published" ) ) )
{
SetWriter ( item , userId ) ;
repository . AddOrUpdate ( item ) ;
updated . Add ( item ) ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
uow . Commit ( ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
foreach ( var c in updated )
{
var xml = c . ToXml ( ) ;
var poco = new ContentXmlDto { NodeId = c . Id , Xml = xml . ToString ( SaveOptions . None ) } ;
var exists = uow . Database . FirstOrDefault < ContentXmlDto > ( "WHERE nodeId = @Id" , new { Id = c . Id } ) ! =
null ;
int result = exists
? uow . Database . Update ( poco )
: Convert . ToInt32 ( uow . Database . Insert ( poco ) ) ;
}
}
//Save xml to db and call following method to fire event:
if ( omitCacheRefresh = = false )
_publishingStrategy . PublishingFinalized ( updated , false ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Publish , "Publish with Children performed by user" , userId = = - 1 ? 0 : userId ,
content . Id ) ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
return published ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
/// UnPublishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.</param>
/// <returns>True if unpublishing succeeded, otherwise False</returns>
public bool UnPublish ( IContent content , int userId = - 1 , bool omitCacheRefresh = false )
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
2012-10-10 12:13:23 -02:00
2012-12-15 11:04:03 -01:00
//Look for children and unpublish them if any exists, otherwise just unpublish the passed in Content.
var children = GetChildrenDeep ( content . Id ) ;
var hasChildren = children . Any ( ) ;
2012-11-01 10:59:32 -01:00
2012-12-15 11:04:03 -01:00
if ( hasChildren )
children . Add ( content ) ;
2012-10-29 14:28:16 -01:00
2012-12-15 11:04:03 -01:00
var unpublished = hasChildren
? _publishingStrategy . UnPublish ( children , userId )
: _publishingStrategy . UnPublish ( content , userId ) ;
2012-11-01 10:59:32 -01:00
2012-12-15 11:04:03 -01:00
if ( unpublished )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
repository . AddOrUpdate ( content ) ;
2012-11-01 10:59:32 -01:00
2012-12-15 11:04:03 -01:00
if ( hasChildren )
{
foreach ( var child in children )
{
SetWriter ( child , userId ) ;
repository . AddOrUpdate ( child ) ;
}
}
2012-10-29 14:28:16 -01:00
2012-12-15 11:04:03 -01:00
//Remove 'published' xml from the cmsContentXml table for the unpublished content and its (possible) children
uow . Database . Delete < ContentXmlDto > ( "WHERE nodeId = @Id" , new { Id = content . Id } ) ;
if ( hasChildren )
{
foreach ( var child in children )
{
uow . Database . Delete < ContentXmlDto > ( "WHERE nodeId = @Id" , new { Id = child . Id } ) ;
}
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
uow . Commit ( ) ;
}
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
if ( omitCacheRefresh = = false )
_publishingStrategy . UnPublishingFinalized ( content ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . UnPublish , "UnPublish performed by user" , userId = = - 1 ? 0 : userId , content . Id ) ;
}
2012-10-10 12:13:23 -02:00
2012-12-15 11:04:03 -01:00
return unpublished ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
/// Saves and Publishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool SaveAndPublish ( IContent content , int userId = - 1 , bool omitCacheRefresh = false )
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
var e = new SaveEventArgs ( ) ;
if ( Saving ! = null )
Saving ( content , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
if ( content . ParentId ! = - 1 & & content . ParentId ! = - 20 & & HasPublishedVersion ( content . ParentId ) = = false )
{
LogHelper . Info < ContentService > (
string . Format (
"Content '{0}' with Id '{1}' could not be published because its parent is not published." ,
content . Name , content . Id ) ) ;
return false ;
}
//Content contains invalid property values and can therefore not be published - fire event?
if ( ! content . IsValid ( ) )
{
LogHelper . Info < ContentService > (
string . Format (
"Content '{0}' with Id '{1}' could not be published because of invalid properties." ,
content . Name , content . Id ) ) ;
return false ;
}
//Publish and then update the database with new status
bool published = _publishingStrategy . Publish ( content , userId ) ;
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
//Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed
SetWriter ( content , userId ) ;
repository . AddOrUpdate ( content ) ;
if ( published )
{
var xml = content . ToXml ( ) ;
var poco = new ContentXmlDto { NodeId = content . Id , Xml = xml . ToString ( SaveOptions . None ) } ;
var exists =
uow . Database . FirstOrDefault < ContentXmlDto > ( "WHERE nodeId = @Id" , new { Id = content . Id } ) ! =
null ;
int result = exists
? uow . Database . Update ( poco )
: Convert . ToInt32 ( uow . Database . Insert ( poco ) ) ;
}
2012-12-11 12:03:36 +05:00
2012-12-14 15:19:54 -01:00
uow . Commit ( ) ;
2012-12-15 11:04:03 -01:00
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
if ( omitCacheRefresh = = false )
_publishingStrategy . PublishingFinalized ( content ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
if ( Saved ! = null )
Saved ( content , e ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Publish , "Save and Publish performed by user" , userId = = - 1 ? 0 : userId , content . Id ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
return published ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
return false ;
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
/// Saves a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save</param>
/// <param name="userId">Optional Id of the User saving the Content</param>
public void Save ( IContent content , int userId = - 1 )
{
var e = new SaveEventArgs ( ) ;
if ( Saving ! = null )
Saving ( content , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
SetWriter ( content , userId ) ;
2012-11-05 14:42:21 -01:00
2012-12-15 11:04:03 -01:00
//Only change the publish state if the "previous" version was actually published
if ( content . Published )
content . ChangePublishedState ( false ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
repository . AddOrUpdate ( content ) ;
uow . Commit ( ) ;
}
if ( Saved ! = null )
Saved ( content , e ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Save , "Save Content performed by user" , userId = = - 1 ? 0 : userId , content . Id ) ;
}
}
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
/// <summary>
/// Saves a collection of <see cref="IContent"/> objects.
/// </summary>
/// <remarks>
/// If the collection of content contains new objects that references eachother by Id or ParentId,
/// then use the overload Save method with a collection of Lazy <see cref="IContent"/>.
/// </remarks>
/// <param name="contents">Collection of <see cref="IContent"/> to save</param>
/// <param name="userId">Optional Id of the User saving the Content</param>
public void Save ( IEnumerable < IContent > contents , int userId = - 1 )
{
var containsNew = contents . Any ( x = > x . HasIdentity = = false ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
var e = new SaveEventArgs ( ) ;
if ( Saving ! = null )
Saving ( contents , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
if ( containsNew )
{
foreach ( var content in contents )
{
SetWriter ( content , userId ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
//Only change the publish state if the "previous" version was actually published
if ( content . Published )
content . ChangePublishedState ( false ) ;
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
repository . AddOrUpdate ( content ) ;
uow . Commit ( ) ;
}
}
else
{
foreach ( var content in contents )
{
SetWriter ( content , userId ) ;
repository . AddOrUpdate ( content ) ;
}
uow . Commit ( ) ;
}
}
if ( Saved ! = null )
Saved ( contents , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Save , "Bulk Save content performed by user" , userId = = - 1 ? 0 : userId , - 1 ) ;
}
}
2012-12-11 12:03:36 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
/// Saves a collection of lazy loaded <see cref="IContent"/> objects.
/// </summary>
/// <remarks>
/// This method ensures that Content is saved lazily, so a new graph of <see cref="IContent"/>
/// objects can be saved in bulk. But note that objects are saved one at a time to ensure Ids.
/// </remarks>
/// <param name="contents">Collection of Lazy <see cref="IContent"/> to save</param>
/// <param name="userId">Optional Id of the User saving the Content</param>
public void Save ( IEnumerable < Lazy < IContent > > contents , int userId = - 1 )
{
var e = new SaveEventArgs ( ) ;
if ( Saving ! = null )
Saving ( contents , e ) ;
if ( ! e . Cancel )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
foreach ( var content in contents )
{
SetWriter ( content . Value , userId ) ;
//Only change the publish state if the "previous" version was actually published
if ( content . Value . Published )
content . Value . ChangePublishedState ( false ) ;
repository . AddOrUpdate ( content . Value ) ;
uow . Commit ( ) ;
}
}
if ( Saved ! = null )
Saved ( contents , e ) ;
Audit . Add ( AuditTypes . Save , "Bulk Save (lazy) content performed by user" , userId = = - 1 ? 0 : userId , - 1 ) ;
}
}
2012-12-11 23:19:07 +05:00
2012-12-14 15:19:54 -01:00
/// <summary>
/// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin.
/// </summary>
/// <remarks>This needs extra care and attention as its potentially a dangerous and extensive operation</remarks>
/// <param name="contentTypeId">Id of the <see cref="IContentType"/></param>
/// <param name="userId">Optional Id of the user issueing the delete operation</param>
public void DeleteContentOfType ( int contentTypeId , int userId = - 1 )
{
2012-12-15 11:04:03 -01:00
var uow = _uowProvider . GetUnitOfWork ( ) ;
var repository = _repositoryFactory . CreateContentRepository ( uow ) ;
//NOTE What about content that has the contenttype as part of its composition?
var query = Query < IContent > . Builder . Where ( x = > x . ContentTypeId = = contentTypeId ) ;
var contents = repository . GetByQuery ( query ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
var e = new DeleteEventArgs { Id = contentTypeId } ;
if ( Deleting ! = null )
Deleting ( contents , e ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
foreach ( var content in contents . OrderByDescending ( x = > x . ParentId ) )
2012-12-14 15:19:54 -01:00
{
2012-12-15 11:04:03 -01:00
//Look for children of current content and move that to trash before the current content is deleted
var c = content ;
var childQuery = Query < IContent > . Builder . Where ( x = > x . Path . StartsWith ( c . Path ) ) ;
var children = repository . GetByQuery ( childQuery ) ;
foreach ( var child in children )
2012-12-14 15:19:54 -01:00
{
2012-12-15 11:04:03 -01:00
if ( child . ContentType . Id ! = contentTypeId )
MoveToRecycleBin ( child , userId ) ;
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
//Permantly delete the content
Delete ( content , userId ) ;
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
uow . Dispose ( ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
if ( Deleted ! = null )
Deleted ( contents , e ) ;
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Delete ,
string . Format ( "Delete Content of Type {0} performed by user" , contentTypeId ) ,
userId = = - 1 ? 0 : userId , - 1 ) ;
2012-12-14 15:19:54 -01:00
}
}
2012-12-15 11:04:03 -01:00
/// <summary>
2012-12-14 15:19:54 -01:00
/// Permanently deletes an <see cref="IContent"/> object.
/// </summary>
/// <remarks>
/// This method will also delete associated media files, child content and possibly associated domains.
/// </remarks>
/// <remarks>Please note that this method will completely remove the Content from the database</remarks>
/// <param name="content">The <see cref="IContent"/> to delete</param>
/// <param name="userId">Optional Id of the User deleting the Content</param>
2012-12-11 23:19:07 +05:00
public void Delete ( IContent content , int userId = - 1 )
{
var e = new DeleteEventArgs { Id = content . Id } ;
if ( Deleting ! = null )
Deleting ( content , e ) ;
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
//Make sure that published content is unpublished before being deleted
if ( HasPublishedVersion ( content . Id ) )
{
UnPublish ( content , userId ) ;
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
//Delete children before deleting the 'possible parent'
var children = GetChildren ( content . Id ) ;
foreach ( var child in children )
{
Delete ( child , userId ) ;
}
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
SetWriter ( content , userId ) ;
repository . Delete ( content ) ;
uow . Commit ( ) ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
if ( Deleted ! = null )
Deleted ( content , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Delete , "Delete Content performed by user" , userId = = - 1 ? 0 : userId , content . Id ) ;
}
2012-12-11 23:19:07 +05:00
}
/// <summary>
/// Permanently deletes versions from an <see cref="IContent"/> object prior to a specific date.
/// </summary>
/// <param name="content">Id of the <see cref="IContent"/> object to delete versions from</param>
/// <param name="versionDate">Latest version date</param>
/// <param name="userId">Optional Id of the User deleting versions of a Content object</param>
public void Delete ( IContent content , DateTime versionDate , int userId = - 1 )
{
Delete ( content . Id , versionDate , userId ) ;
}
/// <summary>
/// Permanently deletes specific version(s) from an <see cref="IContent"/> object.
/// </summary>
/// <param name="content">Id of the <see cref="IContent"/> object to delete a version from</param>
/// <param name="versionId">Id of the version to delete</param>
/// <param name="deletePriorVersions">Boolean indicating whether to delete versions prior to the versionId</param>
/// <param name="userId">Optional Id of the User deleting versions of a Content object</param>
public void Delete ( IContent content , Guid versionId , bool deletePriorVersions , int userId = - 1 )
{
Delete ( content . Id , versionId , deletePriorVersions , userId ) ;
}
/// <summary>
/// Permanently deletes versions from an <see cref="IContent"/> object prior to a specific date.
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/> object to delete versions from</param>
/// <param name="versionDate">Latest version date</param>
/// <param name="userId">Optional Id of the User deleting versions of a Content object</param>
public void Delete ( int id , DateTime versionDate , int userId = - 1 )
{
var e = new DeleteEventArgs { Id = id } ;
if ( Deleting ! = null )
Deleting ( versionDate , e ) ;
if ( ! e . Cancel )
{
2012-12-15 11:04:03 -01:00
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
repository . Delete ( id , versionDate ) ;
2012-12-15 11:04:03 -01:00
uow . Commit ( ) ;
2012-12-11 23:19:07 +05:00
}
2012-12-15 11:04:03 -01:00
if ( Deleted ! = null )
Deleted ( versionDate , e ) ;
Audit . Add ( AuditTypes . Delete , "Delete Content by version date performed by user" , userId = = - 1 ? 0 : userId , - 1 ) ;
2012-12-11 23:19:07 +05:00
}
}
2012-12-15 11:04:03 -01:00
/// <summary>
/// Permanently deletes specific version(s) from an <see cref="IContent"/> object.
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/> object to delete a version from</param>
/// <param name="versionId">Id of the version to delete</param>
/// <param name="deletePriorVersions">Boolean indicating whether to delete versions prior to the versionId</param>
/// <param name="userId">Optional Id of the User deleting versions of a Content object</param>
public void Delete ( int id , Guid versionId , bool deletePriorVersions , int userId = - 1 )
{
if ( deletePriorVersions )
{
var content = GetByIdVersion ( id , versionId ) ;
Delete ( id , content . UpdateDate , userId ) ;
}
2012-11-11 18:07:52 -01:00
2012-12-15 11:04:03 -01:00
var e = new DeleteEventArgs { Id = id } ;
if ( Deleting ! = null )
Deleting ( versionId , e ) ;
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
repository . Delete ( id , versionId ) ;
uow . Commit ( ) ;
}
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
if ( Deleted ! = null )
Deleted ( versionId , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Delete , "Delete Content by version performed by user" , userId = = - 1 ? 0 : userId , - 1 ) ;
}
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
/// Deletes an <see cref="IContent"/> object by moving it to the Recycle Bin
/// </summary>
/// <remarks>Move an item to the Recycle Bin will result in the item being unpublished</remarks>
/// <param name="content">The <see cref="IContent"/> to delete</param>
/// <param name="userId">Optional Id of the User deleting the Content</param>
public void MoveToRecycleBin ( IContent content , int userId = - 1 )
{
var e = new MoveEventArgs { ParentId = - 20 } ;
if ( Trashing ! = null )
Trashing ( content , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
//Make sure that published content is unpublished before being moved to the Recycle Bin
if ( HasPublishedVersion ( content . Id ) )
{
UnPublish ( content , userId ) ;
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
//Move children to Recycle Bin before the 'possible parent' is moved there
var children = GetChildren ( content . Id ) ;
foreach ( var child in children )
{
MoveToRecycleBin ( child , userId ) ;
}
2012-12-14 15:19:54 -01:00
2012-12-15 11:04:03 -01:00
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
SetWriter ( content , userId ) ;
content . ChangeTrashedState ( true ) ;
repository . AddOrUpdate ( content ) ;
uow . Commit ( ) ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
if ( Trashed ! = null )
Trashed ( content , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . Move , "Move Content to Recycle Bin performed by user" , userId = = - 1 ? 0 : userId ,
content . Id ) ;
}
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
/// <summary>
2012-12-11 23:19:07 +05:00
/// Moves an <see cref="IContent"/> object to a new location by changing its parent id.
/// </summary>
/// <remarks>
/// If the <see cref="IContent"/> object is already published it will be
/// published after being moved to its new location. Otherwise it'll just
/// be saved with a new parent id.
/// </remarks>
/// <param name="content">The <see cref="IContent"/> to move</param>
/// <param name="parentId">Id of the Content's new Parent</param>
/// <param name="userId">Optional Id of the User moving the Content</param>
public void Move ( IContent content , int parentId , int userId = - 1 )
{
2012-12-14 15:19:54 -01:00
//TODO Verify that SortOrder + Path is updated correctly
//TODO Add a check to see if parentId = -20 because then we should change the TrashState
2012-12-11 23:19:07 +05:00
var e = new MoveEventArgs { ParentId = parentId } ;
if ( Moving ! = null )
Moving ( content , e ) ;
if ( ! e . Cancel )
{
2012-12-11 12:03:36 +05:00
SetWriter ( content , userId ) ;
2012-12-11 23:19:07 +05:00
//If Content is being moved away from Recycle Bin, its state should be un-trashed
if ( content . Trashed & & parentId ! = - 20 )
{
content . ChangeTrashedState ( false , parentId ) ;
}
else
{
content . ParentId = parentId ;
}
//If Content is published, it should be (re)published from its new location
if ( content . Published )
{
SaveAndPublish ( content , userId ) ;
}
else
{
Save ( content , userId ) ;
}
if ( Moved ! = null )
Moved ( content , e ) ;
Audit . Add ( AuditTypes . Move , "Move Content performed by user" , userId = = - 1 ? 0 : userId , content . Id ) ;
}
}
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
/// </summary>
public void EmptyRecycleBin ( )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
var query = Query < IContent > . Builder . Where ( x = > x . ParentId = = - 20 ) ;
var contents = repository . GetByQuery ( query ) ;
foreach ( var content in contents )
{
repository . Delete ( content ) ;
}
2012-12-11 23:19:07 +05:00
uow . Commit ( ) ;
2012-12-15 11:04:03 -01:00
}
Audit . Add ( AuditTypes . Delete , "Empty Recycle Bin performed by user" , 0 , - 20 ) ;
2012-12-11 23:19:07 +05:00
}
2012-12-14 15:19:54 -01:00
/// <summary>
/// Copies an <see cref="IContent"/> object by creating a new Content object of the same type and copies all data from the current
/// to the new copy which is returned.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to copy</param>
/// <param name="parentId">Id of the Content's new Parent</param>
/// <param name="relateToOriginal">Boolean indicating whether the copy should be related to the original</param>
/// <param name="userId">Optional Id of the User copying the Content</param>
/// <returns>The newly created <see cref="IContent"/> object</returns>
public IContent Copy ( IContent content , int parentId , bool relateToOriginal , int userId = - 1 )
2012-12-11 23:19:07 +05:00
{
var e = new CopyEventArgs { ParentId = parentId } ;
if ( Copying ! = null )
Copying ( content , e ) ;
IContent copy = null ;
if ( ! e . Cancel )
{
copy = ( ( Content ) content ) . Clone ( ) ;
copy . ParentId = parentId ;
copy . Name = copy . Name + " (1)" ;
var uow = _uowProvider . GetUnitOfWork ( ) ;
2012-12-12 10:47:14 -01:00
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
2012-12-11 23:19:07 +05:00
{
2012-12-11 12:03:36 +05:00
SetWriter ( content , userId ) ;
2012-11-14 11:20:21 -01:00
2012-12-11 12:03:36 +05:00
repository . AddOrUpdate ( copy ) ;
2012-12-11 23:19:07 +05:00
uow . Commit ( ) ;
2012-12-14 15:19:54 -01:00
var uploadFieldId = new Guid ( "5032a6e6-69e3-491d-bb28-cd31cd11086c" ) ;
if ( content . Properties . Any ( x = > x . PropertyType . DataTypeControlId = = uploadFieldId ) )
{
bool isUpdated = false ;
var fs = FileSystemProviderManager . Current . GetFileSystemProvider < MediaFileSystem > ( ) ;
//Loop through properties to check if the content contains media that should be deleted
foreach ( var property in content . Properties . Where ( x = > x . PropertyType . DataTypeControlId = = uploadFieldId
& & string . IsNullOrEmpty ( x . Value . ToString ( ) ) = = false ) )
{
if ( fs . FileExists ( IOHelper . MapPath ( property . Value . ToString ( ) ) ) )
{
var currentPath = fs . GetRelativePath ( property . Value . ToString ( ) ) ;
var propertyId = copy . Properties . First ( x = > x . Alias = = property . Alias ) . Id ;
var newPath = fs . GetRelativePath ( propertyId , System . IO . Path . GetFileName ( currentPath ) ) ;
fs . CopyFile ( currentPath , newPath ) ;
copy . SetValue ( property . Alias , fs . GetUrl ( newPath ) ) ;
//Copy thumbnails
foreach ( var thumbPath in fs . GetThumbnails ( currentPath ) )
{
var newThumbPath = fs . GetRelativePath ( propertyId , System . IO . Path . GetFileName ( thumbPath ) ) ;
fs . CopyFile ( thumbPath , newThumbPath ) ;
}
isUpdated = true ;
}
}
if ( isUpdated )
{
repository . AddOrUpdate ( copy ) ;
uow . Commit ( ) ;
}
}
2012-12-11 23:19:07 +05:00
}
2012-12-14 15:19:54 -01:00
//NOTE This 'Relation' part should eventually be delegated to a RelationService
if ( relateToOriginal )
{
RelationType relationType = null ;
using ( var relationTypeRepository = _repositoryFactory . CreateRelationTypeRepository ( uow ) )
{
relationType = relationTypeRepository . Get ( 1 ) ;
}
using ( var relationRepository = _repositoryFactory . CreateRelationRepository ( uow ) )
{
var relation = new Relation ( content . Id , copy . Id , relationType ) ;
relationRepository . AddOrUpdate ( relation ) ;
uow . Commit ( ) ;
}
Audit . Add ( AuditTypes . Copy ,
string . Format ( "Copied content with Id: '{0}' related to original content with Id: '{1}'" ,
copy . Id , content . Id ) , copy . WriterId , copy . Id ) ;
}
//Look for children and copy those as well
var children = GetChildren ( content . Id ) ;
foreach ( var child in children )
{
Copy ( child , copy . Id , relateToOriginal , userId ) ;
}
2012-12-11 23:19:07 +05:00
}
if ( Copied ! = null )
Copied ( copy , e ) ;
2012-12-14 15:19:54 -01:00
Audit . Add ( AuditTypes . Copy , "Copy Content performed by user" , content . WriterId , content . Id ) ;
2012-12-11 23:19:07 +05:00
return copy ;
}
/// <summary>
/// Sends an <see cref="IContent"/> to Publication, which executes handlers and events for the 'Send to Publication' action.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to send to publication</param>
/// <param name="userId">Optional Id of the User issueing the send to publication</param>
/// <returns>True if sending publication was succesfull otherwise false</returns>
2012-12-14 15:19:54 -01:00
internal bool SendToPublication ( IContent content , int userId = - 1 )
2012-12-11 23:19:07 +05:00
{
//TODO Implement something similar to this
var e = new SendToPublishEventArgs ( ) ;
if ( SendingToPublish ! = null )
SendingToPublish ( content , e ) ;
if ( ! e . Cancel )
{
2012-12-15 11:04:03 -01:00
// Do some stuff here.. RunActionHandlers
2012-12-11 23:19:07 +05:00
if ( SentToPublish ! = null )
SentToPublish ( content , e ) ;
Audit . Add ( AuditTypes . SendToPublish , "Send to Publish performed by user" , content . WriterId , content . Id ) ;
2012-12-15 11:04:03 -01:00
return true ;
2012-12-11 23:19:07 +05:00
}
return false ;
}
2012-12-15 11:04:03 -01:00
/// <summary>
/// Rollback an <see cref="IContent"/> object to a previous version.
/// This will create a new version, which is a copy of all the old data.
/// </summary>
/// <remarks>
/// The way data is stored actually only allows us to rollback on properties
/// and not data like Name and Alias of the Content.
/// </remarks>
/// <param name="id">Id of the <see cref="IContent"/>being rolled back</param>
/// <param name="versionId">Id of the version to rollback to</param>
/// <param name="userId">Optional Id of the User issueing the rollback of the Content</param>
/// <returns>The newly created <see cref="IContent"/> object</returns>
public IContent Rollback ( int id , Guid versionId , int userId = - 1 )
{
var e = new RollbackEventArgs ( ) ;
var content = GetByIdVersion ( id , versionId ) ;
2012-11-05 14:42:21 -01:00
2012-12-15 11:04:03 -01:00
if ( Rollingback ! = null )
Rollingback ( content , e ) ;
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
if ( ! e . Cancel )
{
var uow = _uowProvider . GetUnitOfWork ( ) ;
using ( var repository = _repositoryFactory . CreateContentRepository ( uow ) )
{
SetUser ( content , userId ) ;
SetWriter ( content , userId ) ;
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
repository . AddOrUpdate ( content ) ;
uow . Commit ( ) ;
}
2012-11-14 11:20:21 -01:00
2012-12-15 11:04:03 -01:00
if ( Rolledback ! = null )
Rolledback ( content , e ) ;
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
Audit . Add ( AuditTypes . RollBack , "Content rollback performed by user" , content . WriterId , content . Id ) ;
}
2012-10-10 12:13:23 -02:00
2012-12-15 11:04:03 -01:00
return content ;
}
2012-12-11 23:19:07 +05:00
2012-12-15 11:04:03 -01:00
#region Internal Methods
/// <summary>
2012-12-11 23:19:07 +05:00
/// Internal method to set the HttpContextBase for testing.
/// </summary>
/// <param name="httpContext"><see cref="HttpContextBase"/></param>
internal void SetHttpContext ( HttpContextBase httpContext )
{
_httpContext = httpContext ;
}
2012-12-15 11:04:03 -01:00
#endregion
#region Private Methods
/// <summary>
/// Gets a flat list of decendents of content from parent id
/// </summary>
/// <remarks>
/// Only contains valid <see cref="IContent"/> objects, which means
/// that everything in the returned list can be published.
/// If an invalid <see cref="IContent"/> object is found it will not
/// be added to the list neither will its children.
/// </remarks>
/// <param name="parentId">Id of the parent to retrieve children from</param>
/// <returns>A list of valid <see cref="IContent"/> that can be published</returns>
private List < IContent > GetChildrenDeep ( int parentId )
{
var list = new List < IContent > ( ) ;
var children = GetChildren ( parentId ) ;
foreach ( var child in children )
{
if ( child . IsValid ( ) )
{
list . Add ( child ) ;
list . AddRange ( GetChildrenDeep ( child . Id ) ) ;
}
}
return list ;
}
2012-12-11 23:19:07 +05:00
/// <summary>
/// Updates a content object with the User (id), who created the content.
/// </summary>
/// <param name="content"><see cref="IContent"/> object to update</param>
/// <param name="userId">Optional Id of the User</param>
private void SetUser ( IContent content , int userId )
{
if ( userId > - 1 )
{
//If a user id was passed in we use that
content . CreatorId = userId ;
}
else if ( UserServiceOrContext ( ) )
{
var profile = _httpContext = = null
? _userService . GetCurrentBackOfficeUser ( )
: _userService . GetCurrentBackOfficeUser ( _httpContext ) ;
content . CreatorId = profile . Id . SafeCast < int > ( ) ;
}
else
{
//Otherwise we default to Admin user, which should always exist (almost always)
content . CreatorId = 0 ;
}
}
/// <summary>
/// Updates a content object with a Writer (user id), who updated the content.
/// </summary>
/// <param name="content"><see cref="IContent"/> object to update</param>
/// <param name="userId">Optional Id of the Writer</param>
private void SetWriter ( IContent content , int userId )
{
if ( userId > - 1 )
{
//If a user id was passed in we use that
content . WriterId = userId ;
}
else if ( UserServiceOrContext ( ) )
{
var profile = _httpContext = = null
? _userService . GetCurrentBackOfficeUser ( )
: _userService . GetCurrentBackOfficeUser ( _httpContext ) ;
content . WriterId = profile . Id . SafeCast < int > ( ) ;
}
else
{
//Otherwise we default to Admin user, which should always exist (almost always)
content . WriterId = 0 ;
}
}
private bool UserServiceOrContext ( )
{
return _userService ! = null & & ( HttpContext . Current ! = null | | _httpContext ! = null ) ;
}
2012-12-15 11:04:03 -01:00
#endregion
#region Event Handlers
/// <summary>
2012-12-11 23:19:07 +05:00
/// Occurs before Delete
/// </summary>
public static event EventHandler < DeleteEventArgs > Deleting ;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event EventHandler < DeleteEventArgs > Deleted ;
/// <summary>
/// Occurs before Save
/// </summary>
public static event EventHandler < SaveEventArgs > Saving ;
/// <summary>
/// Occurs after Save
/// </summary>
public static event EventHandler < SaveEventArgs > Saved ;
/// <summary>
/// Occurs before Create
/// </summary>
public static event EventHandler < NewEventArgs > Creating ;
/// <summary>
/// Occurs after Create
/// </summary>
public static event EventHandler < NewEventArgs > Created ;
/// <summary>
/// Occurs before Copy
/// </summary>
public static event EventHandler < CopyEventArgs > Copying ;
/// <summary>
/// Occurs after Copy
/// </summary>
public static event EventHandler < CopyEventArgs > Copied ;
/// <summary>
/// Occurs before Content is moved to Recycle Bin
/// </summary>
public static event EventHandler < MoveEventArgs > Trashing ;
/// <summary>
/// Occurs after Content is moved to Recycle Bin
/// </summary>
public static event EventHandler < MoveEventArgs > Trashed ;
/// <summary>
/// Occurs before Move
/// </summary>
public static event EventHandler < MoveEventArgs > Moving ;
/// <summary>
/// Occurs after Move
/// </summary>
public static event EventHandler < MoveEventArgs > Moved ;
/// <summary>
/// Occurs before Rollback
/// </summary>
public static event EventHandler < RollbackEventArgs > Rollingback ;
/// <summary>
/// Occurs after Rollback
/// </summary>
public static event EventHandler < RollbackEventArgs > Rolledback ;
/// <summary>
/// Occurs before Send to Publish
/// </summary>
public static event EventHandler < SendToPublishEventArgs > SendingToPublish ;
/// <summary>
/// Occurs after Send to Publish
/// </summary>
public static event EventHandler < SendToPublishEventArgs > SentToPublish ;
#endregion
}
2012-10-03 12:51:32 -02:00
}