Implements U4-943 to the extent its currently possible.
Refactoring publishing methods in the ContentService. Adding tests for the QueryBuilder.
This commit is contained in:
32
src/Umbraco.Core/EventArgs.cs
Normal file
32
src/Umbraco.Core/EventArgs.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
//Publishing Events
|
||||
public class PublishEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
public class UnPublishEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
public class SendToPublishEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
|
||||
//Moving Content Events
|
||||
public class MoveEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
public class MoveToTrashEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
|
||||
//Copying Content Events
|
||||
public class CopyEventArgs : System.ComponentModel.CancelEventArgs
|
||||
{
|
||||
public int CopyTo { get; set; }
|
||||
public IContent NewContent { get; set; }
|
||||
}
|
||||
|
||||
//Rollback Content Event
|
||||
public class RollbackEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
|
||||
//Content Cache Event args
|
||||
public class ContentCacheEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
public class RefreshContentEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
|
||||
//Generel eventArgs
|
||||
public class DeleteEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
public class SaveEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
public class NewEventArgs : System.ComponentModel.CancelEventArgs { }
|
||||
}
|
||||
@@ -225,7 +225,7 @@ namespace Umbraco.Core.Models
|
||||
/// Changes the Published state of the content object
|
||||
/// </summary>
|
||||
/// <param name="isPublished">Boolean indicating whether content is published (true) or unpublished (false)</param>
|
||||
internal void ChangePublishedState(bool isPublished)
|
||||
public void ChangePublishedState(bool isPublished)
|
||||
{
|
||||
Published = isPublished;
|
||||
//NOTE Should this be checked against the Expire/Release dates?
|
||||
@@ -237,7 +237,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
|
||||
/// <param name="parentId"> </param>
|
||||
internal void ChangeTrashedState(bool isTrashed, int parentId = -1)
|
||||
public void ChangeTrashedState(bool isTrashed, int parentId = -1)
|
||||
{
|
||||
Trashed = isTrashed;
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
internal void ResetDirtyProperties()
|
||||
public void ResetDirtyProperties()
|
||||
{
|
||||
_propertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
{
|
||||
bool IsDirty();
|
||||
bool IsPropertyDirty(string propName);
|
||||
void ResetDirtyProperties();
|
||||
}
|
||||
}
|
||||
@@ -52,5 +52,18 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="contentType">New ContentType for this content</param>
|
||||
/// <param name="clearProperties">Boolean indicating whether to clear PropertyTypes upon change</param>
|
||||
void ChangeContentType(IContentType contentType, bool clearProperties);
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Published state of the content object
|
||||
/// </summary>
|
||||
/// <param name="isPublished">Boolean indicating whether content is published (true) or unpublished (false)</param>
|
||||
void ChangePublishedState(bool isPublished);
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Trashed state of the content object
|
||||
/// </summary>
|
||||
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
|
||||
/// <param name="parentId"> </param>
|
||||
void ChangeTrashedState(bool isTrashed, int parentId = -1);
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,9 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
|
||||
internal override string Map(string propertyName)
|
||||
{
|
||||
if (!PropertyInfoCache.ContainsKey(propertyName))
|
||||
return string.Empty;
|
||||
|
||||
var dtoTypeProperty = PropertyInfoCache[propertyName];
|
||||
|
||||
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
|
||||
|
||||
@@ -12,29 +12,29 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
public void GetTableInfo(Type t, TableInfo ti)
|
||||
{ }
|
||||
|
||||
public bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn)
|
||||
public bool MapPropertyToColumn(Type t, PropertyInfo pi, ref string columnName, ref bool resultColumn)
|
||||
{
|
||||
if (pi.DeclaringType == typeof(Content) || pi.DeclaringType == typeof(IContent))
|
||||
if (t == typeof(Content) || t == typeof(IContent))
|
||||
{
|
||||
var mappedName = ContentMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(Models.Media) || pi.DeclaringType == typeof(IMedia))
|
||||
if (t == typeof(Models.Media) || t == typeof(IMedia))
|
||||
{
|
||||
var mappedName = MediaMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(ContentType) || pi.DeclaringType == typeof(IContentType) || pi.DeclaringType == typeof(IMediaType))
|
||||
if (t == typeof(ContentType) || t == typeof(IContentType) || t == typeof(IMediaType))
|
||||
{
|
||||
var mappedName = ContentTypeMapper.Instance.Map(pi.Name);
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
@@ -44,47 +44,47 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(DataTypeDefinition) || pi.DeclaringType == typeof(IDataTypeDefinition))
|
||||
if (t == typeof(DataTypeDefinition) || t == typeof(IDataTypeDefinition))
|
||||
{
|
||||
var mappedName = DataTypeDefinitionMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(DictionaryItem) || pi.DeclaringType == typeof(IDictionaryItem))
|
||||
if (t == typeof(DictionaryItem) || t == typeof(IDictionaryItem))
|
||||
{
|
||||
var mappedName = DictionaryMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(DictionaryTranslation) || pi.DeclaringType == typeof(IDictionaryTranslation))
|
||||
if (t == typeof(DictionaryTranslation) || t == typeof(IDictionaryTranslation))
|
||||
{
|
||||
var mappedName = DictionaryTranslationMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(Language) || pi.DeclaringType == typeof(ILanguage))
|
||||
if (t == typeof(Language) || t == typeof(ILanguage))
|
||||
{
|
||||
var mappedName = LanguageMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(Relation))
|
||||
if (t == typeof(Relation))
|
||||
{
|
||||
var mappedName = RelationMapper.Instance.Map(pi.Name);
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
@@ -94,33 +94,33 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(RelationType))
|
||||
if (t == typeof(RelationType))
|
||||
{
|
||||
var mappedName = RelationTypeMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(PropertyType))
|
||||
if (t == typeof(PropertyType))
|
||||
{
|
||||
var mappedName = PropertyTypeMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(PropertyGroup))
|
||||
if (t == typeof(PropertyGroup))
|
||||
{
|
||||
var mappedName = PropertyGroupMapper.Instance.Map(pi.Name);
|
||||
if (mappedName == string.Empty)
|
||||
return false;
|
||||
|
||||
columnName = mappedName;
|
||||
if (!string.IsNullOrEmpty(mappedName))
|
||||
{
|
||||
columnName = mappedName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Umbraco.Core.Persistence
|
||||
public interface IMapper
|
||||
{
|
||||
void GetTableInfo(Type t, TableInfo ti);
|
||||
bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn);
|
||||
bool MapPropertyToColumn(Type t, PropertyInfo pi, ref string columnName, ref bool resultColumn);
|
||||
Func<object, object> GetFromDbConverter(PropertyInfo pi, Type SourceType);
|
||||
Func<object, object> GetToDbConverter(Type SourceType);
|
||||
}
|
||||
@@ -1802,7 +1802,7 @@ namespace Umbraco.Core.Persistence
|
||||
if (pc.ColumnName == null)
|
||||
{
|
||||
pc.ColumnName = pi.Name;
|
||||
if (Database.Mapper != null && !Database.Mapper.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn))
|
||||
if (Database.Mapper != null && !Database.Mapper.MapPropertyToColumn(t, pi, ref pc.ColumnName, ref pc.ResultColumn))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", r);
|
||||
case "StartsWith":
|
||||
return string.Format("upper({0}) starting with {1} ", r, args[0].ToString().ToUpper());
|
||||
return string.Format("upper({0}) like '{1}%'", r, RemoveQuote(args[0].ToString().ToUpper()));
|
||||
case "EndsWith":
|
||||
return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper());
|
||||
case "Contains":
|
||||
|
||||
@@ -4,6 +4,10 @@ using System.Linq.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Query Builder for building LINQ translatable queries
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class Query<T> : IQuery<T>
|
||||
{
|
||||
private readonly ExpressionHelper<T> _expresionist = new ExpressionHelper<T>();
|
||||
@@ -32,7 +36,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public List<string> WhereClauses()
|
||||
{
|
||||
return _wheres;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Sql Translator for translating a <see cref="IQuery"/> object to Sql
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class SqlTranslator<T>
|
||||
{
|
||||
private readonly Sql _sql;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
|
||||
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
|
||||
<Compile Include="EventArgs.cs" />
|
||||
<Compile Include="Models\ContentBase.cs" />
|
||||
<Compile Include="Models\ContentExtensions.cs" />
|
||||
<Compile Include="Enum.cs" />
|
||||
|
||||
82
src/Umbraco.Tests/Persistence/Querying/QueryBuilderTests.cs
Normal file
82
src/Umbraco.Tests/Persistence/Querying/QueryBuilderTests.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Querying
|
||||
{
|
||||
[TestFixture]
|
||||
public class QueryBuilderTests : BaseUsingSqlCeSyntax
|
||||
{
|
||||
[Test]
|
||||
public void Can_Build_StartsWith_Query_For_IContent()
|
||||
{
|
||||
// Arrange
|
||||
var sql = new Sql();
|
||||
sql.Select("*");
|
||||
sql.From("umbracoNode");
|
||||
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
|
||||
|
||||
// Act
|
||||
var translator = new SqlTranslator<IContent>(sql, query);
|
||||
var result = translator.Translate();
|
||||
var strResult = result.SQL;
|
||||
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (upper([umbracoNode].[path]) like '-1%')";
|
||||
|
||||
// Assert
|
||||
Assert.That(strResult, Is.Not.Empty);
|
||||
Assert.That(strResult, Is.EqualTo(expectedResult));
|
||||
Console.WriteLine(strResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Build_ParentId_Query_For_IContent()
|
||||
{
|
||||
// Arrange
|
||||
var sql = new Sql();
|
||||
sql.Select("*");
|
||||
sql.From("umbracoNode");
|
||||
|
||||
var query = Query<IContent>.Builder.Where(x => x.ParentId == -1);
|
||||
|
||||
// Act
|
||||
var translator = new SqlTranslator<IContent>(sql, query);
|
||||
var result = translator.Translate();
|
||||
var strResult = result.SQL;
|
||||
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (([umbracoNode].[parentID]=-1))";
|
||||
|
||||
// Assert
|
||||
Assert.That(strResult, Is.Not.Empty);
|
||||
Assert.That(strResult, Is.EqualTo(expectedResult));
|
||||
Console.WriteLine(strResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Build_ContentTypeAlias_Query_For_IContentType()
|
||||
{
|
||||
// Arrange
|
||||
var sql = new Sql();
|
||||
sql.Select("*");
|
||||
sql.From("umbracoNode");
|
||||
|
||||
var query = Query<IContentType>.Builder.Where(x => x.Alias == "umbTextpage");
|
||||
|
||||
// Act
|
||||
var translator = new SqlTranslator<IContentType>(sql, query);
|
||||
var result = translator.Translate();
|
||||
var strResult = result.SQL;
|
||||
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (([cmsContentType].[alias]='umbTextpage'))";
|
||||
|
||||
// Assert
|
||||
Assert.That(strResult, Is.Not.Empty);
|
||||
Assert.That(strResult, Is.EqualTo(expectedResult));
|
||||
Console.WriteLine(strResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
Normal file
20
src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers
|
||||
{
|
||||
[TestFixture]
|
||||
public abstract class BaseUsingSqlCeSyntax
|
||||
{
|
||||
[SetUp]
|
||||
public virtual void Initialize()
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntaxProvider.Instance;
|
||||
|
||||
SetUp();
|
||||
}
|
||||
|
||||
public virtual void SetUp()
|
||||
{}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,7 @@
|
||||
<Compile Include="Persistence\Mappers\RelationTypeMapperTest.cs" />
|
||||
<Compile Include="Persistence\MySqlDatabaseCreationTest.cs" />
|
||||
<Compile Include="Persistence\MySqlTableByTableTest.cs" />
|
||||
<Compile Include="Persistence\Querying\QueryBuilderTests.cs" />
|
||||
<Compile Include="Persistence\RepositoryResolverTests.cs" />
|
||||
<Compile Include="Persistence\SqlCeTableByTableTest.cs" />
|
||||
<Compile Include="Persistence\SqlTableByTableTest.cs" />
|
||||
@@ -144,6 +145,7 @@
|
||||
<Compile Include="Routing\RenderRouteHandlerTests.cs" />
|
||||
<Compile Include="Routing\RouteTestExtensions.cs" />
|
||||
<Compile Include="Stubs\TestControllerFactory.cs" />
|
||||
<Compile Include="TestHelpers\BaseUsingSqlCeSyntax.cs" />
|
||||
<Compile Include="TestHelpers\BaseWebTest.cs" />
|
||||
<Compile Include="TestHelpers\BaseDatabaseTest.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedContent.cs" />
|
||||
@@ -261,6 +263,9 @@
|
||||
<Content Include="Masterpages\dummy.txt" />
|
||||
<Content Include="Views\dummy.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Persistence\Repositories\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(ProjectDir)"..\..\lib\SQLCE4\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /D
|
||||
|
||||
87
src/Umbraco.Web/Publishing/BasePublishingStrategy.cs
Normal file
87
src/Umbraco.Web/Publishing/BasePublishingStrategy.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Publishing
|
||||
{
|
||||
public abstract class BasePublishingStrategy : IPublishingStrategy
|
||||
{
|
||||
public abstract bool Publish(IContent content, int userId);
|
||||
public abstract bool PublishWithChildren(IEnumerable<IContent> children, int userId);
|
||||
public abstract bool UnPublish(IContent content, int userId);
|
||||
|
||||
/// <summary>
|
||||
/// The publish event handler
|
||||
/// </summary>
|
||||
public delegate void PublishEventHandler(IContent sender, PublishEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// The unpublish event handler
|
||||
/// </summary>
|
||||
public delegate void UnPublishEventHandler(IContent sender, UnPublishEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before publish
|
||||
/// </summary>
|
||||
public static event PublishEventHandler BeforePublish;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:BeforePublish"/> event
|
||||
/// </summary>
|
||||
/// <param name="content"> </param>
|
||||
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void FireBeforePublish(IContent content, PublishEventArgs e)
|
||||
{
|
||||
if (BeforePublish != null)
|
||||
BeforePublish(content, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after publish
|
||||
/// </summary>
|
||||
public static event PublishEventHandler AfterPublish;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:AfterPublish"/> event
|
||||
/// </summary>
|
||||
/// <param name="content"> </param>
|
||||
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void FireAfterPublish(IContent content, PublishEventArgs e)
|
||||
{
|
||||
if (AfterPublish != null)
|
||||
AfterPublish(content, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before unpublish
|
||||
/// </summary>
|
||||
public static event UnPublishEventHandler BeforeUnPublish;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:BeforeUnPublish"/> event
|
||||
/// </summary>
|
||||
/// <param name="content"> </param>
|
||||
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void FireBeforeUnPublish(IContent content, UnPublishEventArgs e)
|
||||
{
|
||||
if (BeforeUnPublish != null)
|
||||
BeforeUnPublish(content, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after unpublish
|
||||
/// </summary>
|
||||
public static event UnPublishEventHandler AfterUnPublish;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:AfterUnPublish"/> event
|
||||
/// </summary>
|
||||
/// <param name="content"> </param>
|
||||
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void FireAfterUnPublish(IContent content, UnPublishEventArgs e)
|
||||
{
|
||||
if (AfterUnPublish != null)
|
||||
AfterUnPublish(content, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ namespace Umbraco.Web.Publishing
|
||||
{
|
||||
bool Publish(IContent content, int userId);
|
||||
bool PublishWithChildren(IEnumerable<IContent> children, int userId);
|
||||
void PublishWithSubs(IContent content, int userId);
|
||||
bool UnPublish(IContent content, int userId);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,109 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
|
||||
namespace Umbraco.Web.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// Currently acts as an interconnection between the new public api and the legacy api for publishing
|
||||
/// </summary>
|
||||
internal class PublishingStrategy : IPublishingStrategy
|
||||
internal class PublishingStrategy : BasePublishingStrategy
|
||||
{
|
||||
internal PublishingStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Publish(IContent content, int userId)
|
||||
/// <summary>
|
||||
/// Publishes a single piece of content
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Id of the user issueing the publish</param>
|
||||
/// <returns>True if the content was published, otherwise false</returns>
|
||||
public override bool Publish(IContent content, int userId)
|
||||
{
|
||||
//Fire BeforePublish event
|
||||
/*PublishEventArgs e = new PublishEventArgs();
|
||||
FireBeforePublish(e);*/
|
||||
|
||||
//Create new (unpublished) version - Guid is returned
|
||||
//Log Publish
|
||||
//Update all cmsDocument entries with Id to newest=0
|
||||
//Insert new version in cmsDocument table
|
||||
//Set Release and Expire date on newly created version
|
||||
var e = new PublishEventArgs();
|
||||
FireBeforePublish(content, e);
|
||||
|
||||
// Update xml in db using the new document (has correct version date)
|
||||
//newDoc.XmlGenerate(new XmlDocument());
|
||||
if (!e.Cancel)
|
||||
{
|
||||
content.ChangePublishedState(true);
|
||||
|
||||
//Fire AfterPublish event
|
||||
//FireAfterPublish(e);
|
||||
//Fire AfterPublish event
|
||||
FireAfterPublish(content, e);
|
||||
|
||||
//Updating the cache is not done in the Document-Publish methods, so this part should be added
|
||||
//global::umbraco.library.UpdateDocumentCache(doc.Id);
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
content.Name, content.Id));
|
||||
|
||||
int contentId = content.Id;
|
||||
//NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
|
||||
|
||||
var doc = new Document(contentId, true);
|
||||
var user = new User(userId);
|
||||
|
||||
return doc.PublishWithResult(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool PublishWithChildren(IEnumerable<IContent> children, int userId)
|
||||
/// <summary>
|
||||
/// Publishes a list of content
|
||||
/// </summary>
|
||||
/// <param name="children">List of <see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Id of the user issueing the publish</param>
|
||||
/// <returns>True if the content was published, otherwise false</returns>
|
||||
public override bool PublishWithChildren(IEnumerable<IContent> children, int userId)
|
||||
{
|
||||
int contentId = children.Last().Id;
|
||||
var doc = new Document(contentId, true);
|
||||
var user = new User(userId);
|
||||
return doc.PublishWithChildrenWithResult(user);
|
||||
//Fire BeforePublish event
|
||||
var e = new PublishEventArgs();
|
||||
|
||||
if (e.Cancel)
|
||||
return false;
|
||||
|
||||
foreach (var content in children)
|
||||
{
|
||||
FireBeforePublish(content, e);
|
||||
|
||||
content.ChangePublishedState(true);
|
||||
|
||||
//Fire AfterPublish event
|
||||
FireAfterPublish(content, e);
|
||||
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
content.Name, content.Id));
|
||||
}
|
||||
|
||||
//NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void PublishWithSubs(IContent content, int userId)
|
||||
/// <summary>
|
||||
/// Unpublishes a single piece of content
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to unpublish</param>
|
||||
/// <param name="userId">Id of the user issueing the unpublish</param>
|
||||
/// <returns>True is the content was unpublished, otherwise false</returns>
|
||||
public override bool UnPublish(IContent content, int userId)
|
||||
{
|
||||
int contentId = content.Id;
|
||||
var doc = new Document(contentId, true);
|
||||
var user = new User(userId);
|
||||
doc.PublishWithSubs(user);
|
||||
}
|
||||
var e = new UnPublishEventArgs();
|
||||
FireBeforeUnPublish(content, e);
|
||||
|
||||
if (!e.Cancel)
|
||||
{
|
||||
content.ChangePublishedState(false);
|
||||
|
||||
FireAfterUnPublish(content, e);
|
||||
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
|
||||
content.Name, content.Id));
|
||||
|
||||
//NOTE: Ideally the xml cache should be refreshed here - as part of the unpublishing
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool UnPublish(IContent content, int userId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -204,27 +205,34 @@ namespace Umbraco.Web.Services
|
||||
|
||||
var list = new List<IContent>();
|
||||
|
||||
//Consider creating a Path query instead of recursive method
|
||||
//Consider creating a Path query instead of recursive method:
|
||||
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
|
||||
|
||||
var rootContent = GetRootContent();
|
||||
foreach (var content in rootContent)
|
||||
{
|
||||
list.AddRange(GetChildrenDeep(content.Id));
|
||||
}
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
//Only publish valid content - Might need to change the flat list as it could pose problems for children of invalid content
|
||||
if(item.IsValid())
|
||||
if(content.IsValid())
|
||||
{
|
||||
((Content)item).ChangePublishedState(true);
|
||||
repository.AddOrUpdate(item);
|
||||
list.AddRange(GetChildrenDeep(content.Id));
|
||||
}
|
||||
}
|
||||
|
||||
unitOfWork.Commit();
|
||||
//Publish and then update the database with new status
|
||||
var published = _publishingStrategy.PublishWithChildren(list, userId);
|
||||
if (published)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
repository.AddOrUpdate(item);
|
||||
}
|
||||
|
||||
return _publishingStrategy.PublishWithChildren(list, userId);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
|
||||
global::umbraco.library.RefreshContent();
|
||||
}
|
||||
|
||||
return published;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -249,25 +257,48 @@ namespace Umbraco.Web.Services
|
||||
var unitOfWork = _provider.GetUnitOfWork();
|
||||
var repository = RepositoryResolver.ResolveByType<IContentRepository, IContent, int>(unitOfWork);
|
||||
|
||||
//Consider creating a Path query instead of recursive method
|
||||
//Check if parent is published - if parent isn't published this Content cannot be published
|
||||
var parent = GetById(content.ParentId);
|
||||
if (!parent.Published)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//Consider creating a Path query instead of recursive method:
|
||||
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path));
|
||||
|
||||
var list = GetChildrenDeep(content.Id);
|
||||
list.Add(content);
|
||||
|
||||
foreach (var item in list)
|
||||
//Publish and then update the database with new status
|
||||
var published = _publishingStrategy.PublishWithChildren(list, userId);
|
||||
if (published)
|
||||
{
|
||||
//TODO Test and correct this so children of unpublished content isn't published.
|
||||
//Only publish valid content - Might need to change the flat list as it could pose problems for children of invalid content
|
||||
if (item.IsValid())
|
||||
foreach (var item in list)
|
||||
{
|
||||
((Content) item).ChangePublishedState(true);
|
||||
repository.AddOrUpdate(item);
|
||||
}
|
||||
|
||||
unitOfWork.Commit();
|
||||
|
||||
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
|
||||
//TODO Need to investigate if it will also update the cache for children of the Content object
|
||||
global::umbraco.library.UpdateDocumentCache(content.Id);
|
||||
}
|
||||
|
||||
unitOfWork.Commit();
|
||||
|
||||
return _publishingStrategy.PublishWithChildren(list, userId);
|
||||
return published;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -281,26 +312,42 @@ namespace Umbraco.Web.Services
|
||||
var unitOfWork = _provider.GetUnitOfWork();
|
||||
var repository = RepositoryResolver.ResolveByType<IContentRepository, IContent, int>(unitOfWork);
|
||||
|
||||
((Content)content).ChangePublishedState(false);
|
||||
repository.AddOrUpdate(content);
|
||||
unitOfWork.Commit();
|
||||
var unpublished = _publishingStrategy.UnPublish(content, userId);
|
||||
|
||||
return _publishingStrategy.UnPublish(content, userId);
|
||||
if (unpublished)
|
||||
{
|
||||
repository.AddOrUpdate(content);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content class.
|
||||
global::umbraco.library.UnPublishSingleNode(content.Id);
|
||||
}
|
||||
|
||||
return unpublished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a flat list of decendents of content from parent id
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <returns></returns>
|
||||
/// <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)
|
||||
{
|
||||
list.Add(child);
|
||||
list.AddRange(GetChildrenDeep(child.Id));
|
||||
if (child.IsValid())
|
||||
{
|
||||
list.Add(child);
|
||||
list.AddRange(GetChildrenDeep(child.Id));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -316,16 +363,37 @@ namespace Umbraco.Web.Services
|
||||
var unitOfWork = _provider.GetUnitOfWork();
|
||||
var repository = RepositoryResolver.ResolveByType<IContentRepository, IContent, int>(unitOfWork);
|
||||
|
||||
//NOTE: Should also check if parent is published - if parent isn't published this Content cannot be published
|
||||
//Check if parent is published - if parent isn't published this Content cannot be published
|
||||
var parent = GetById(content.ParentId);
|
||||
if(!parent.Published)
|
||||
{
|
||||
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())
|
||||
return false;//Content contains invalid property values and can therefore not be published
|
||||
{
|
||||
LogHelper.Info<ContentService>(
|
||||
string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
|
||||
content.Name, content.Id));
|
||||
return false;
|
||||
}
|
||||
|
||||
((Content)content).ChangePublishedState(true);
|
||||
repository.AddOrUpdate(content);
|
||||
unitOfWork.Commit();
|
||||
//Publish and then update the database with new status
|
||||
bool published = _publishingStrategy.Publish(content, userId);
|
||||
if (published)
|
||||
{
|
||||
repository.AddOrUpdate(content);
|
||||
unitOfWork.Commit();
|
||||
|
||||
return _publishingStrategy.Publish(content, userId);
|
||||
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
|
||||
global::umbraco.library.UpdateDocumentCache(content.Id);
|
||||
}
|
||||
|
||||
return published;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -306,6 +306,7 @@
|
||||
<Compile Include="Mvc\UmbracoPageResult.cs" />
|
||||
<Compile Include="PropertyEditors\RteMacroRenderingPropertyEditorValueConverter.cs" />
|
||||
<Compile Include="PublishedMediaStoreResolver.cs" />
|
||||
<Compile Include="Publishing\BasePublishingStrategy.cs" />
|
||||
<Compile Include="Publishing\IPublishingStrategy.cs" />
|
||||
<Compile Include="Publishing\PublishingStrategy.cs" />
|
||||
<Compile Include="RenderFieldCaseType.cs" />
|
||||
|
||||
Reference in New Issue
Block a user