U4-4847 Refactor ContentService (#1266)
* U4-4748 - refactor Content-, Media- and MemberTypeRepository * Cleanup Attempt * Cleanup OperationStatus * U4-4748 - refactor Content-, Media- and MemberTypeService * U4-4748 - cleanup locking * U4-4748 - refactor Content-, Media- and MemberRepository * U4-4748 - refactor ContentService (in progress) * U4-4748 - all unit of work must be completed * U4-4748 - refactor locks, fix tests * U4-4748 - deal with fixmes * U4-4748 - lock table migration * Update UmbracoVersion * Fix AuthorizeUpgrade * U4-4748 - cleanup+bugfix lock objects * U4-4748 - bugfix * updates a string interpolation
This commit is contained in:
committed by
Shannon Deminick
parent
12f4873c90
commit
ddf38407d8
@@ -1,174 +1,128 @@
|
||||
using System;
|
||||
using Umbraco.Core.Dynamics;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the result of an operation attempt.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
[Serializable]
|
||||
public struct Attempt<T>
|
||||
{
|
||||
private readonly bool _success;
|
||||
private readonly T _result;
|
||||
private readonly Exception _exception;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Attempt{T}"/> was successful.
|
||||
/// </summary>
|
||||
public bool Success
|
||||
{
|
||||
get { return _success; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception associated with an unsuccessful attempt.
|
||||
/// </summary>
|
||||
public Exception Exception { get { return _exception; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception associated with an unsuccessful attempt.
|
||||
/// </summary>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete(".Error is obsolete, you should use .Exception instead.", false)]
|
||||
public Exception Error { get { return _exception; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attempt result.
|
||||
/// </summary>
|
||||
public T Result
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
// optimize, use a singleton failed attempt
|
||||
private static readonly Attempt<T> Failed = new Attempt<T>(false, default(T), null);
|
||||
|
||||
/// <summary>
|
||||
/// Represents an unsuccessful attempt.
|
||||
/// </summary>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete(".Failed is obsolete, you should use Attempt<T>.Fail() instead.", false)]
|
||||
public static readonly Attempt<T> False = Failed;
|
||||
|
||||
// private - use Succeed() or Fail() methods to create attempts
|
||||
private Attempt(bool success, T result, Exception exception)
|
||||
{
|
||||
_success = success;
|
||||
_result = result;
|
||||
_exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="Attempt{T}"/> struct with a result.
|
||||
/// </summary>
|
||||
/// <param name="success">A value indicating whether the attempt is successful.</param>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete("Attempt ctors are obsolete, you should use Attempt<T>.Succeed(), Attempt<T>.Fail() or Attempt<T>.If() instead.", false)]
|
||||
public Attempt(bool success, T result)
|
||||
: this(success, result, null)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="Attempt{T}"/> struct representing a failed attempt, with an exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete("Attempt ctors are obsolete, you should use Attempt<T>.Succeed(), Attempt<T>.Fail() or Attempt<T>.If() instead.", false)]
|
||||
public Attempt(Exception exception)
|
||||
: this(false, default(T), exception)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful attempt.
|
||||
/// </summary>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed()
|
||||
{
|
||||
return new Attempt<T>(true, default(T), null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed(T result)
|
||||
{
|
||||
return new Attempt<T>(true, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt.
|
||||
/// </summary>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail()
|
||||
{
|
||||
return Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with an exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(Exception exception)
|
||||
{
|
||||
return new Attempt<T>(false, default(T), exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(T result)
|
||||
{
|
||||
return new Attempt<T>(false, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result and an exception.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(T result, Exception exception)
|
||||
{
|
||||
return new Attempt<T>(false, result, exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt.
|
||||
/// </summary>
|
||||
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> SucceedIf(bool condition)
|
||||
{
|
||||
return condition ? new Attempt<T>(true, default(T), null) : Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt, with a result.
|
||||
/// </summary>
|
||||
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> SucceedIf(bool condition, T result)
|
||||
{
|
||||
return new Attempt<T>(condition, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicity operator to check if the attempt was successful without having to access the 'success' property
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator bool(Attempt<T> a)
|
||||
{
|
||||
return a.Success;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the result of an operation attempt.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
[Serializable]
|
||||
public struct Attempt<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Attempt{T}"/> was successful.
|
||||
/// </summary>
|
||||
public bool Success { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception associated with an unsuccessful attempt.
|
||||
/// </summary>
|
||||
public Exception Exception { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attempt result.
|
||||
/// </summary>
|
||||
public T Result { get; }
|
||||
|
||||
// optimize, use a singleton failed attempt
|
||||
private static readonly Attempt<T> Failed = new Attempt<T>(false, default(T), null);
|
||||
|
||||
// private - use Succeed() or Fail() methods to create attempts
|
||||
private Attempt(bool success, T result, Exception exception)
|
||||
{
|
||||
Success = success;
|
||||
Result = result;
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful attempt.
|
||||
/// </summary>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed()
|
||||
{
|
||||
return new Attempt<T>(true, default(T), null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed(T result)
|
||||
{
|
||||
return new Attempt<T>(true, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt.
|
||||
/// </summary>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail()
|
||||
{
|
||||
return Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with an exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(Exception exception)
|
||||
{
|
||||
return new Attempt<T>(false, default(T), exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(T result)
|
||||
{
|
||||
return new Attempt<T>(false, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result and an exception.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(T result, Exception exception)
|
||||
{
|
||||
return new Attempt<T>(false, result, exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt.
|
||||
/// </summary>
|
||||
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> SucceedIf(bool condition)
|
||||
{
|
||||
return condition ? new Attempt<T>(true, default(T), null) : Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt, with a result.
|
||||
/// </summary>
|
||||
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> SucceedIf(bool condition, T result)
|
||||
{
|
||||
return new Attempt<T>(condition, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicity operator to check if the attempt was successful without having to access the 'success' property
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator bool(Attempt<T> a)
|
||||
{
|
||||
return a.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public static readonly Guid DocumentGuid = new Guid(Document);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document Type object.
|
||||
/// </summary>
|
||||
@@ -84,6 +89,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media object.
|
||||
/// </summary>
|
||||
public static readonly Guid MediaGuid = new Guid(Media);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Media Recycle Bin.
|
||||
/// </summary>
|
||||
@@ -143,7 +153,10 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string LockObject = "87A9F1FF-B1E4-4A25-BABB-465A4A47EC41";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Lock object.
|
||||
/// </summary>
|
||||
public static readonly Guid LockObjectGuid = new Guid(LockObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,6 @@
|
||||
public const int DefaultContentListViewDataTypeId = -95;
|
||||
public const int DefaultMediaListViewDataTypeId = -96;
|
||||
public const int DefaultMembersListViewDataTypeId = -97;
|
||||
|
||||
// identifiers for lock objects
|
||||
public const int ServersLock = -331;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,34 +19,33 @@ namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
public void Compose(IServiceRegistry container)
|
||||
{
|
||||
container.RegisterSingleton<IPublishingStrategy, PublishingStrategy>();
|
||||
|
||||
// register a transient messages factory, which will be replaced byt the web
|
||||
// boot manager when running in a web context
|
||||
container.Register<IEventMessagesFactory, TransientEventMessagesFactory>();
|
||||
|
||||
|
||||
//the context
|
||||
container.RegisterSingleton<ServiceContext>();
|
||||
|
||||
|
||||
//now the services...
|
||||
container.RegisterSingleton<IMigrationEntryService, MigrationEntryService>();
|
||||
container.RegisterSingleton<IPublicAccessService, PublicAccessService>();
|
||||
container.RegisterSingleton<ITaskService, TaskService>();
|
||||
container.RegisterSingleton<IDomainService, DomainService>();
|
||||
container.RegisterSingleton<IAuditService, AuditService>();
|
||||
container.RegisterSingleton<IAuditService, AuditService>();
|
||||
container.RegisterSingleton<ITagService, TagService>();
|
||||
container.RegisterSingleton<IContentService, ContentService>();
|
||||
container.RegisterSingleton<IUserService, UserService>();
|
||||
container.RegisterSingleton<IMemberService, MemberService>();
|
||||
container.RegisterSingleton<IMediaService, MediaService>();
|
||||
container.RegisterSingleton<IContentTypeService, ContentTypeService>();
|
||||
container.RegisterSingleton<IMediaTypeService, MediaTypeService>();
|
||||
container.RegisterSingleton<IDataTypeService, DataTypeService>();
|
||||
container.RegisterSingleton<IFileService, FileService>();
|
||||
container.RegisterSingleton<ILocalizationService, LocalizationService>();
|
||||
container.RegisterSingleton<IPackagingService, PackagingService>();
|
||||
container.RegisterSingleton<IServerRegistrationService, ServerRegistrationService>();
|
||||
container.RegisterSingleton<IEntityService, EntityService>();
|
||||
container.RegisterSingleton<IRelationService, RelationService>();
|
||||
container.RegisterSingleton<IRelationService, RelationService>();
|
||||
container.RegisterSingleton<IMacroService, MacroService>();
|
||||
container.RegisterSingleton<IMemberTypeService, MemberTypeService>();
|
||||
container.RegisterSingleton<IMemberGroupService, MemberGroupService>();
|
||||
@@ -84,7 +83,7 @@ namespace Umbraco.Core.DependencyInjection
|
||||
factory.GetInstance<Lazy<LocalizedTextServiceFileSources>>(),
|
||||
factory.GetInstance<ILogger>()));
|
||||
|
||||
//TODO: These are replaced in the web project - we need to declare them so that
|
||||
//TODO: These are replaced in the web project - we need to declare them so that
|
||||
// something is wired up, just not sure this is very nice but will work for now.
|
||||
container.RegisterSingleton<IApplicationTreeService, EmptyApplicationTreeService>();
|
||||
container.RegisterSingleton<ISectionService, EmptySectionService>();
|
||||
|
||||
@@ -17,6 +17,16 @@ namespace Umbraco.Core.Events
|
||||
Files = new List<string>();
|
||||
}
|
||||
|
||||
public RecycleBinEventArgs(Guid nodeObjectType, bool emptiedSuccessfully)
|
||||
: base(false)
|
||||
{
|
||||
AllPropertyData = new Dictionary<int, IEnumerable<Property>>();
|
||||
NodeObjectType = nodeObjectType;
|
||||
Ids = new int[0];
|
||||
RecycleBinEmptiedSuccessfully = emptiedSuccessfully;
|
||||
Files = new List<string>();
|
||||
}
|
||||
|
||||
public RecycleBinEventArgs(Guid nodeObjectType, Dictionary<int, IEnumerable<Property>> allPropertyData)
|
||||
: base(true)
|
||||
{
|
||||
@@ -26,6 +36,15 @@ namespace Umbraco.Core.Events
|
||||
Files = new List<string>();
|
||||
}
|
||||
|
||||
public RecycleBinEventArgs(Guid nodeObjectType)
|
||||
: base(true)
|
||||
{
|
||||
AllPropertyData = new Dictionary<int, IEnumerable<Property>>();
|
||||
NodeObjectType = nodeObjectType;
|
||||
Ids = new int[0];
|
||||
Files = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Backwards compatibility constructor
|
||||
/// </summary>
|
||||
|
||||
@@ -4,8 +4,10 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Hosting;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -306,7 +308,7 @@ namespace Umbraco.Core.IO
|
||||
var debugFolder = Path.Combine(binFolder, "debug");
|
||||
if (Directory.Exists(debugFolder))
|
||||
return debugFolder;
|
||||
#endif
|
||||
#endif
|
||||
var releaseFolder = Path.Combine(binFolder, "release");
|
||||
if (Directory.Exists(releaseFolder))
|
||||
return releaseFolder;
|
||||
@@ -341,7 +343,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public static void EnsurePathExists(string path)
|
||||
{
|
||||
var absolutePath = IOHelper.MapPath(path);
|
||||
var absolutePath = MapPath(path);
|
||||
if (Directory.Exists(absolutePath) == false)
|
||||
Directory.CreateDirectory(absolutePath);
|
||||
}
|
||||
@@ -349,14 +351,58 @@ namespace Umbraco.Core.IO
|
||||
public static void EnsureFileExists(string path, string contents)
|
||||
{
|
||||
var absolutePath = IOHelper.MapPath(path);
|
||||
if (File.Exists(absolutePath) == false)
|
||||
if (File.Exists(absolutePath)) return;
|
||||
|
||||
using (var writer = File.CreateText(absolutePath))
|
||||
{
|
||||
using (var writer = File.CreateText(absolutePath))
|
||||
{
|
||||
writer.Write(contents);
|
||||
}
|
||||
writer.Write(contents);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all files passed in.
|
||||
/// </summary>
|
||||
/// <param name="files"></param>
|
||||
/// <param name="onError"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool DeleteFiles(IEnumerable<string> files, Action<string, Exception> onError = null)
|
||||
{
|
||||
//ensure duplicates are removed
|
||||
files = files.Distinct();
|
||||
|
||||
var allsuccess = true;
|
||||
|
||||
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
|
||||
Parallel.ForEach(files, file =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (file.IsNullOrWhiteSpace()) return;
|
||||
|
||||
var relativeFilePath = fs.GetRelativePath(file);
|
||||
if (fs.FileExists(relativeFilePath) == false) return;
|
||||
|
||||
var parentDirectory = Path.GetDirectoryName(relativeFilePath);
|
||||
|
||||
// don't want to delete the media folder if not using directories.
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories && parentDirectory != fs.GetRelativePath("/"))
|
||||
{
|
||||
//issue U4-771: if there is a parent directory the recursive parameter should be true
|
||||
fs.DeleteDirectory(parentDirectory, String.IsNullOrEmpty(parentDirectory) == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.DeleteFile(file, true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
onError?.Invoke(file, e);
|
||||
allsuccess = false;
|
||||
}
|
||||
});
|
||||
|
||||
return allsuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,14 @@ namespace Umbraco.Core.Models
|
||||
private IContentType _contentType;
|
||||
private ITemplate _template;
|
||||
private bool _published;
|
||||
private bool? _publishedOriginal;
|
||||
private string _language;
|
||||
private DateTime? _releaseDate;
|
||||
private DateTime? _expireDate;
|
||||
private int _writer;
|
||||
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
|
||||
private bool _permissionsChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
/// </summary>
|
||||
@@ -31,8 +33,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Content(string name, IContent parent, IContentType contentType)
|
||||
: this(name, parent, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
@@ -47,6 +48,7 @@ namespace Umbraco.Core.Models
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentType = contentType;
|
||||
PublishedState = PublishedState.Unpublished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,8 +59,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Content(string name, int parentId, IContentType contentType)
|
||||
: this(name, parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
@@ -73,6 +74,7 @@ namespace Umbraco.Core.Models
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentType = contentType;
|
||||
PublishedState = PublishedState.Unpublished;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo TemplateSelector = ExpressionHelper.GetPropertyInfo<Content, ITemplate>(x => x.Template);
|
||||
@@ -95,7 +97,13 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public virtual ITemplate Template
|
||||
{
|
||||
get { return _template; }
|
||||
get
|
||||
{
|
||||
if (_template == null)
|
||||
return _contentType.DefaultTemplate;
|
||||
|
||||
return _template;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
@@ -146,11 +154,19 @@ namespace Umbraco.Core.Models
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_published = value;
|
||||
_publishedOriginal = _publishedOriginal ?? _published;
|
||||
PublishedState = _published ? PublishedState.Published : PublishedState.Unpublished;
|
||||
return _published;
|
||||
}, _published, PublishedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool PublishedOriginal
|
||||
{
|
||||
get { return _publishedOriginal ?? false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Language of the data contained within this Content object.
|
||||
/// </summary>
|
||||
@@ -305,12 +321,14 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public void ChangePublishedState(PublishedState state)
|
||||
{
|
||||
Published = state == PublishedState.Published;
|
||||
if (state == PublishedState.Published || state == PublishedState.Unpublished)
|
||||
throw new ArgumentException("Invalid state.");
|
||||
Published = state == PublishedState.Publishing;
|
||||
PublishedState = state;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal PublishedState PublishedState { get; set; }
|
||||
internal PublishedState PublishedState { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier of the published version, if any.
|
||||
@@ -322,24 +340,26 @@ namespace Umbraco.Core.Models
|
||||
/// Gets a value indicating whether the content has a published version.
|
||||
/// </summary>
|
||||
public bool HasPublishedVersion { get { return PublishedVersionGuid != default(Guid); } }
|
||||
|
||||
/// <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>
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
{
|
||||
Trashed = isTrashed;
|
||||
ParentId = parentId;
|
||||
|
||||
//If the content is trashed and is published it should be marked as unpublished
|
||||
if (isTrashed && Published)
|
||||
{
|
||||
ChangePublishedState(PublishedState.Unpublished);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
base.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
|
||||
// take care of the published state
|
||||
switch (PublishedState)
|
||||
{
|
||||
case PublishedState.Saving:
|
||||
case PublishedState.Unpublishing:
|
||||
PublishedState = PublishedState.Unpublished;
|
||||
break;
|
||||
case PublishedState.Publishing:
|
||||
PublishedState = PublishedState.Published;
|
||||
break;
|
||||
}
|
||||
|
||||
_publishedOriginal = _published;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being updated
|
||||
/// </summary>
|
||||
@@ -377,6 +397,8 @@ namespace Umbraco.Core.Models
|
||||
property.Version = clone.Version;
|
||||
}
|
||||
|
||||
clone.PublishedVersionGuid = Guid.Empty;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,16 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ParentId from the lazy integer id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
internal protected void SetLazyParentId(Lazy<int> parentId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the entity
|
||||
/// </summary>
|
||||
@@ -483,8 +493,6 @@ namespace Umbraco.Core.Models
|
||||
get { return _lastInvalidProperties; }
|
||||
}
|
||||
|
||||
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -20);
|
||||
|
||||
#region Dirty property handling
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -17,9 +14,6 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -43,175 +37,184 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item should be persisted at all
|
||||
/// Determines whether the content should be persisted.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// In one particular case, a content item shouldn't be persisted:
|
||||
/// * The item exists and is published
|
||||
/// * A call to ContentService.Save is made
|
||||
/// * The item has not been modified whatsoever apart from changing it's published status from published to saved
|
||||
///
|
||||
/// In this case, there is no reason to make any database changes at all
|
||||
/// </remarks>
|
||||
/// <param name="entity">The content.</param>
|
||||
/// <returns>True is the content should be persisted, otherwise false.</returns>
|
||||
/// <remarks>See remarks in overload.</remarks>
|
||||
internal static bool RequiresSaving(this IContent entity)
|
||||
{
|
||||
var publishedState = ((Content)entity).PublishedState;
|
||||
return RequiresSaving(entity, publishedState);
|
||||
return RequiresSaving(entity, ((Content) entity).PublishedState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item should be persisted at all
|
||||
/// Determines whether the content should be persisted.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="publishedState"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="entity">The content.</param>
|
||||
/// <param name="publishedState">The published state of the content.</param>
|
||||
/// <returns>True is the content should be persisted, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// In one particular case, a content item shouldn't be persisted:
|
||||
/// * The item exists and is published
|
||||
/// * A call to ContentService.Save is made
|
||||
/// * The item has not been modified whatsoever apart from changing it's published status from published to saved
|
||||
///
|
||||
/// In this case, there is no reason to make any database changes at all
|
||||
/// This is called by the repository when persisting an existing content, to
|
||||
/// figure out whether it needs to persist the content at all.
|
||||
/// </remarks>
|
||||
internal static bool RequiresSaving(this IContent entity, PublishedState publishedState)
|
||||
{
|
||||
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
|
||||
//check if any user prop has changed
|
||||
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
|
||||
|
||||
//We need to know if any other property apart from Published was changed here
|
||||
//don't create a new version if the published state has changed to 'Save' but no data has actually been changed
|
||||
if (publishedChanged && entity.Published == false && propertyValueChanged == false)
|
||||
// note: publishedState is always the entity's PublishedState except for tests
|
||||
|
||||
var content = (Content) entity;
|
||||
var userPropertyChanged = content.IsAnyUserPropertyDirty();
|
||||
var dirtyProps = content.GetDirtyProperties();
|
||||
//var contentPropertyChanged = content.IsEntityDirty();
|
||||
var contentPropertyChangedExceptPublished = dirtyProps.Any(x => x != "Published");
|
||||
|
||||
// we don't want to save (write to DB) if we are "saving" either a published content
|
||||
// (.Saving) or an unpublished content (.Unpublished) and strictly nothing has changed
|
||||
|
||||
var noSave = (publishedState == PublishedState.Saving || publishedState == PublishedState.Unpublished)
|
||||
&& userPropertyChanged == false
|
||||
&& contentPropertyChangedExceptPublished == false;
|
||||
|
||||
return noSave == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a new version of the content should be created.
|
||||
/// </summary>
|
||||
/// <param name="entity">The content.</param>
|
||||
/// <returns>True if a new version should be created, otherwise false.</returns>
|
||||
/// <remarks>See remarks in overload.</remarks>
|
||||
internal static bool RequiresNewVersion(this IContent entity)
|
||||
{
|
||||
return RequiresNewVersion(entity, ((Content) entity).PublishedState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a new version of the content should be created.
|
||||
/// </summary>
|
||||
/// <param name="entity">The content.</param>
|
||||
/// <param name="publishedState">The published state of the content.</param>
|
||||
/// <returns>True if a new version should be created, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// This is called by the repository when persisting an existing content, to
|
||||
/// figure out whether it needs to create a new version for that content.
|
||||
/// A new version needs to be created when:
|
||||
/// * The publish status is changed
|
||||
/// * The language is changed
|
||||
/// * A content property is changed (? why ?)
|
||||
/// * The item is already published and is being published again and any property value is changed (to enable a rollback)
|
||||
/// </remarks>
|
||||
internal static bool RequiresNewVersion(this IContent entity, PublishedState publishedState)
|
||||
{
|
||||
// note: publishedState is always the entity's PublishedState except for tests
|
||||
|
||||
// read
|
||||
// http://issues.umbraco.org/issue/U4-2589 (save & publish & creating new versions)
|
||||
// http://issues.umbraco.org/issue/U4-3404 (pressing preview does save then preview)
|
||||
// http://issues.umbraco.org/issue/U4-5510 (previewing & creating new versions)
|
||||
//
|
||||
// slightly modifying the rules to make more sense (marked with CHANGE)
|
||||
// but should respect the result of the discussions in those issues
|
||||
|
||||
// figure out whether .Language has changed
|
||||
// this language stuff was an old POC and should be removed
|
||||
var hasLanguageChanged = entity.IsPropertyDirty("Language");
|
||||
if (hasLanguageChanged)
|
||||
return true; // language change => new version
|
||||
|
||||
var content = (Content) entity;
|
||||
//var contentPropertyChanged = content2.IsEntityDirty();
|
||||
var userPropertyChanged = content.IsAnyUserPropertyDirty();
|
||||
var dirtyProps = content.GetDirtyProperties();
|
||||
var contentPropertyChangedExceptPublished = dirtyProps.Any(x => x != "Published");
|
||||
var wasPublished = content.PublishedOriginal;
|
||||
|
||||
switch (publishedState)
|
||||
{
|
||||
//at this point we need to check if any non property value has changed that wasn't the published state
|
||||
var changedProps = ((TracksChangesEntityBase)entity).GetDirtyProperties();
|
||||
if (changedProps.Any(x => x != "Published") == false)
|
||||
{
|
||||
case PublishedState.Publishing:
|
||||
// changed state, publishing either a published or an unpublished version:
|
||||
// DO create a new (published) version IF it was published already AND
|
||||
// anything has changed, else can reuse the current version
|
||||
return (contentPropertyChangedExceptPublished || userPropertyChanged) && wasPublished;
|
||||
|
||||
case PublishedState.Unpublishing:
|
||||
// changed state, unpublishing a published version:
|
||||
// DO create a new (draft) version and preserve the (formerly) published
|
||||
// version for rollback purposes IF the version that's being saved is the
|
||||
// published version, else it's a draft that we can reuse
|
||||
return wasPublished;
|
||||
|
||||
case PublishedState.Saving:
|
||||
// changed state, saving a published version:
|
||||
// DO create a new (draft) version and preserve the published version IF
|
||||
// anything has changed, else do NOT create a new version (pointless)
|
||||
return contentPropertyChangedExceptPublished || userPropertyChanged;
|
||||
|
||||
case PublishedState.Published:
|
||||
// unchanged state, saving a published version:
|
||||
// (can happen eg when moving content, never otherwise)
|
||||
// do NOT create a new version as we're just saving after operations (eg
|
||||
// move) that cannot be rolled back anyway - ensure that's really it
|
||||
if (userPropertyChanged)
|
||||
throw new InvalidOperationException("Invalid PublishedState \"Published\" with user property changes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
case PublishedState.Unpublished:
|
||||
// unchanged state, saving an unpublished version:
|
||||
// do NOT create a new version for user property changes,
|
||||
// BUT create a new version in case of content property changes, for
|
||||
// rollback purposes
|
||||
return contentPropertyChangedExceptPublished;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a new version should be created
|
||||
/// Determines whether the database published flag should be cleared for versions
|
||||
/// other than this content version.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="entity">The content.</param>
|
||||
/// <returns>True if the published flag should be cleared, otherwise false.</returns>
|
||||
/// <returns>See remarks in overload.</returns>
|
||||
internal static bool RequiresClearPublishedFlag(this IContent entity)
|
||||
{
|
||||
var publishedState = ((Content) entity).PublishedState;
|
||||
var requiresNewVersion = entity.RequiresNewVersion(publishedState);
|
||||
return entity.RequiresClearPublishedFlag(publishedState, requiresNewVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the database published flag should be cleared for versions
|
||||
/// other than this content version.
|
||||
/// </summary>
|
||||
/// <param name="entity">The content.</param>
|
||||
/// <param name="publishedState">The published state of the content.</param>
|
||||
/// <param name="isNewVersion">Indicates whether the content is a new version.</param>
|
||||
/// <returns>True if the published flag should be cleared, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// A new version needs to be created when:
|
||||
/// * The publish status is changed
|
||||
/// * The language is changed
|
||||
/// * The item is already published and is being published again and any property value is changed (to enable a rollback)
|
||||
/// This is called by the repository when persisting an existing content, to
|
||||
/// figure out whether it needs to clear the published flag for other versions.
|
||||
/// </remarks>
|
||||
internal static bool ShouldCreateNewVersion(this IContent entity)
|
||||
internal static bool RequiresClearPublishedFlag(this IContent entity, PublishedState publishedState, bool isNewVersion)
|
||||
{
|
||||
var publishedState = ((Content)entity).PublishedState;
|
||||
return ShouldCreateNewVersion(entity, publishedState);
|
||||
}
|
||||
// note: publishedState is always the entity's PublishedState except for tests
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all dirty user defined properties
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> GetDirtyUserProperties(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
|
||||
}
|
||||
|
||||
public static bool IsAnyUserPropertyDirty(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.IsDirty());
|
||||
}
|
||||
|
||||
public static bool WasAnyUserPropertyDirty(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.WasDirty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a new version should be created
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="publishedState"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// A new version needs to be created when:
|
||||
/// * The publish status is changed
|
||||
/// * The language is changed
|
||||
/// * The item is already published and is being published again and any property value is changed (to enable a rollback)
|
||||
/// </remarks>
|
||||
internal static bool ShouldCreateNewVersion(this IContent entity, PublishedState publishedState)
|
||||
{
|
||||
//check if the published state has changed or the language
|
||||
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
|
||||
var langChanged = entity.IsPropertyDirty("Language");
|
||||
var contentChanged = publishedChanged || langChanged;
|
||||
|
||||
//check if any user prop has changed
|
||||
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
|
||||
|
||||
//return true if published or language has changed
|
||||
if (contentChanged)
|
||||
{
|
||||
// new, published version => everything else must be cleared
|
||||
if (isNewVersion && entity.Published)
|
||||
return true;
|
||||
}
|
||||
|
||||
//check if any content prop has changed
|
||||
var contentDataChanged = ((Content)entity).IsEntityDirty();
|
||||
// if that entity was published then that entity has the flag and
|
||||
// it does not need to be cleared for other versions
|
||||
// NOT TRUE when unpublishing we create a NEW version
|
||||
//var wasPublished = ((Content)entity).PublishedOriginal;
|
||||
//if (wasPublished)
|
||||
// return false;
|
||||
|
||||
//return true if the item is published and a property has changed or if any content property has changed
|
||||
return (propertyValueChanged && publishedState == PublishedState.Published) || contentDataChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the published db flag should be set to true for the current entity version and all other db
|
||||
/// versions should have their flag set to false.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is determined by:
|
||||
/// * If a new version is being created and the entity is published
|
||||
/// * If the published state has changed and the entity is published OR the entity has been un-published.
|
||||
/// </remarks>
|
||||
internal static bool ShouldClearPublishedFlagForPreviousVersions(this IContent entity)
|
||||
{
|
||||
var publishedState = ((Content)entity).PublishedState;
|
||||
return entity.ShouldClearPublishedFlagForPreviousVersions(publishedState, entity.ShouldCreateNewVersion(publishedState));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the published db flag should be set to true for the current entity version and all other db
|
||||
/// versions should have their flag set to false.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="publishedState"></param>
|
||||
/// <param name="isCreatingNewVersion"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is determined by:
|
||||
/// * If a new version is being created and the entity is published
|
||||
/// * If the published state has changed and the entity is published OR the entity has been un-published.
|
||||
/// </remarks>
|
||||
internal static bool ShouldClearPublishedFlagForPreviousVersions(this IContent entity, PublishedState publishedState, bool isCreatingNewVersion)
|
||||
{
|
||||
if (isCreatingNewVersion && entity.Published)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//If Published state has changed then previous versions should have their publish state reset.
|
||||
//If state has been changed to unpublished the previous versions publish state should also be reset.
|
||||
if (entity.IsPropertyDirty("Published") && (entity.Published || publishedState == PublishedState.Unpublished))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// clear whenever we are publishing or unpublishing
|
||||
// publishing: because there might be a previously published version, which needs to be cleared
|
||||
// unpublishing: same - we might be a saved version, not the published one, which needs to be cleared
|
||||
return publishedState == PublishedState.Publishing || publishedState == PublishedState.Unpublishing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -312,9 +315,9 @@ namespace Umbraco.Core.Models
|
||||
return content.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Contains(recycleBinId.ToInvariantString());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes characters that are not valide XML characters from all entity properties
|
||||
/// Removes characters that are not valide XML characters from all entity properties
|
||||
/// of type string. See: http://stackoverflow.com/a/961504/5018
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
@@ -454,7 +457,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value)
|
||||
{
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
@@ -597,7 +600,7 @@ namespace Umbraco.Core.Models
|
||||
#endregion
|
||||
|
||||
#region User/Profile methods
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this media item.
|
||||
/// </summary>
|
||||
@@ -672,7 +675,7 @@ namespace Umbraco.Core.Models
|
||||
///// <param name="tagGroup"></param>
|
||||
///// <returns></returns>
|
||||
///// <remarks>
|
||||
///// The tags returned are only relavent for published content & saved media or members
|
||||
///// The tags returned are only relavent for published content & saved media or members
|
||||
///// </remarks>
|
||||
//public static IEnumerable<ITag> GetTags(this IContentBase content, string propertyTypeAlias, string tagGroup = "default")
|
||||
//{
|
||||
@@ -909,5 +912,24 @@ namespace Umbraco.Core.Models
|
||||
return ((PackagingService)(packagingService)).Export(member);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dirty
|
||||
|
||||
public static IEnumerable<string> GetDirtyUserProperties(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
|
||||
}
|
||||
|
||||
public static bool IsAnyUserPropertyDirty(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.IsDirty());
|
||||
}
|
||||
|
||||
public static bool WasAnyUserPropertyDirty(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.WasDirty());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -152,31 +152,5 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
return DeepCloneWithResetIdentities(alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IContentType DeepCloneWithResetIdentities(string alias)
|
||||
{
|
||||
var clone = (ContentType)DeepClone();
|
||||
clone.Alias = alias;
|
||||
clone.Key = Guid.Empty;
|
||||
foreach (var propertyGroup in clone.PropertyGroups)
|
||||
{
|
||||
propertyGroup.ResetIdentity();
|
||||
propertyGroup.ResetDirtyProperties(false);
|
||||
}
|
||||
foreach (var propertyType in clone.PropertyTypes)
|
||||
{
|
||||
propertyType.ResetIdentity();
|
||||
propertyType.ResetDirtyProperties(false);
|
||||
}
|
||||
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -642,5 +642,26 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public IContentType DeepCloneWithResetIdentities(string alias)
|
||||
{
|
||||
var clone = (ContentType)DeepClone();
|
||||
clone.Alias = alias;
|
||||
clone.Key = Guid.Empty;
|
||||
foreach (var propertyGroup in clone.PropertyGroups)
|
||||
{
|
||||
propertyGroup.ResetIdentity();
|
||||
propertyGroup.ResetDirtyProperties(false);
|
||||
}
|
||||
foreach (var propertyType in clone.PropertyTypes)
|
||||
{
|
||||
propertyType.ResetIdentity();
|
||||
propertyType.ResetDirtyProperties(false);
|
||||
}
|
||||
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ namespace Umbraco.Core.Models
|
||||
public static IEnumerable<IContentTypeBase> Descendants(this IContentTypeBase contentType)
|
||||
{
|
||||
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
|
||||
var descendants = contentTypeService.GetContentTypeChildren(contentType.Id)
|
||||
.SelectRecursive(type => contentTypeService.GetContentTypeChildren(type.Id));
|
||||
var descendants = contentTypeService.GetChildren(contentType.Id)
|
||||
.SelectRecursive(type => contentTypeService.GetChildren(type.Id));
|
||||
return descendants;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,12 +72,5 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <returns>True if content is valid otherwise false</returns>
|
||||
bool IsValid();
|
||||
|
||||
/// <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 = -20);
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,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>
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
public void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
{
|
||||
Trashed = isTrashed;
|
||||
//The Media Recycle Bin Id is -21 so we correct that here
|
||||
|
||||
@@ -522,11 +522,6 @@ namespace Umbraco.Core.Models
|
||||
get { return _contentType; }
|
||||
}
|
||||
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
{
|
||||
throw new NotSupportedException("Members can't be trashed as no Recycle Bin exists, so use of this method is invalid");
|
||||
}
|
||||
|
||||
/* Internal experiment - only used for mapping queries.
|
||||
* Adding these to have first level properties instead of the Properties collection.
|
||||
*/
|
||||
|
||||
@@ -166,10 +166,10 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
switch (itemType)
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
contentType = ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias);
|
||||
contentType = ApplicationContext.Current.Services.ContentTypeService.Get(alias);
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
contentType = ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias);
|
||||
contentType = ApplicationContext.Current.Services.MediaTypeService.Get(alias);
|
||||
break;
|
||||
case PublishedItemType.Member:
|
||||
contentType = ApplicationContext.Current.Services.MemberTypeService.Get(alias);
|
||||
|
||||
@@ -1,9 +1,54 @@
|
||||
namespace Umbraco.Core.Models
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The <c>IContent</c> states of a content version.
|
||||
/// </summary>
|
||||
public enum PublishedState
|
||||
{
|
||||
// when a content version is loaded, its state is one of those two:
|
||||
|
||||
/// <summary>
|
||||
/// The version is published.
|
||||
/// </summary>
|
||||
Published,
|
||||
|
||||
/// <summary>
|
||||
/// The version is not published.
|
||||
/// </summary>
|
||||
/// <remarks>Also: the version is being saved, in order to register changes
|
||||
/// made to an unpublished version of the content.</remarks>
|
||||
Unpublished,
|
||||
Saved
|
||||
|
||||
// legacy - remove
|
||||
[Obsolete("kill!", true)]
|
||||
Saved,
|
||||
|
||||
// when it is saved, its state can also be one of those:
|
||||
|
||||
/// <summary>
|
||||
/// The version is being saved, in order to register changes made to a published content.
|
||||
/// </summary>
|
||||
/// <remarks>The <value>Saving</value> state is transitional. Once the version
|
||||
/// is saved, its state changes to <value>Unpublished</value>.</remarks>
|
||||
Saving,
|
||||
|
||||
/// <summary>
|
||||
/// The version is being saved, in order to publish the content.
|
||||
/// </summary>
|
||||
/// <remarks>The <value>Publishing</value> state is transitional. Once the version
|
||||
/// is saved, its state changes to <value>Published</value>. The content is published,
|
||||
/// and all other versions are unpublished.</remarks>
|
||||
Publishing,
|
||||
|
||||
/// <summary>
|
||||
/// The version is being saved, in order to unpublish the content.
|
||||
/// </summary>
|
||||
/// <remarks>The <value>Unpublishing</value> state is transitional. Once the version
|
||||
/// is saved, its state changes to <value>Unpublished</value>. The content and all
|
||||
/// other versions are unpublished.</remarks>
|
||||
Unpublishing
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoLock")]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class LockDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(Name = "PK_umbracoLock")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("value")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
public int Value { get; set; } = 1;
|
||||
|
||||
[Column("name")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Length(64)]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
static partial class Constants
|
||||
{
|
||||
public static class Locks
|
||||
{
|
||||
public const int Servers = -331;
|
||||
public const int ContentTypes = -332;
|
||||
public const int ContentTree = -333;
|
||||
public const int MediaTree = -334;
|
||||
public const int MemberTree = -335;
|
||||
public const int MediaTypes = -336;
|
||||
public const int MemberTypes = -337;
|
||||
public const int Domains = -338;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,6 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null,
|
||||
ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null,
|
||||
Version = dto.ContentVersionDto.VersionId,
|
||||
PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished,
|
||||
PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId
|
||||
};
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
|
||||
@@ -27,14 +27,19 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
/// <param name="tableName">Name of the table to create base data for</param>
|
||||
public void InitializeBaseData(string tableName)
|
||||
{
|
||||
_logger.Info<BaseDataCreation>(string.Format("Creating data in table {0}", tableName));
|
||||
_logger.Info<BaseDataCreation>($"Creating data in table {tableName}");
|
||||
|
||||
if(tableName.Equals("umbracoNode"))
|
||||
{
|
||||
CreateUmbracNodeData();
|
||||
CreateUmbracoNodeData();
|
||||
}
|
||||
|
||||
if(tableName.Equals("cmsContentType"))
|
||||
if (tableName.Equals("umbracoLock"))
|
||||
{
|
||||
CreateUmbracoLockData();
|
||||
}
|
||||
|
||||
if (tableName.Equals("cmsContentType"))
|
||||
{
|
||||
CreateCmsContentTypeData();
|
||||
}
|
||||
@@ -102,7 +107,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
_logger.Info<BaseDataCreation>(string.Format("Done creating data in table {0}", tableName));
|
||||
}
|
||||
|
||||
private void CreateUmbracNodeData()
|
||||
private void CreateUmbracoNodeData()
|
||||
{
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -1, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1", SortOrder = 0, UniqueId = new Guid("916724a5-173d-4619-b97e-b9de133dd6f5"), Text = "SYSTEM DATA: umbraco master root", NodeObjectType = new Guid(Constants.ObjectTypes.SystemRoot), CreateDate = DateTime.Now });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -20, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,-20", SortOrder = 0, UniqueId = new Guid("0F582A79-1E41-4CF0-BFA0-76340651891A"), Text = "Recycle Bin", NodeObjectType = new Guid(Constants.ObjectTypes.ContentRecycleBin), CreateDate = DateTime.Now });
|
||||
@@ -135,15 +140,28 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = new Guid(Constants.ObjectTypes.MemberType), CreateDate = DateTime.Now });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1045, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1045", SortOrder = 2, UniqueId = new Guid("7E3962CC-CE20-4FFC-B661-5897A894BA7E"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
|
||||
|
||||
|
||||
//TODO: We're not creating these for 7.0
|
||||
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1038, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1038", SortOrder = 2, UniqueId = new Guid("1251c96c-185c-4e9b-93f4-b48205573cbd"), Text = "Simple Editor", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
|
||||
|
||||
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1042, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1042", SortOrder = 2, UniqueId = new Guid("0a452bd5-83f9-4bc3-8403-1286e13fb77e"), Text = "Macro Container", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
}
|
||||
|
||||
private void CreateUmbracoLockData()
|
||||
{
|
||||
// all lock objects
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.Servers, Name = "Servers" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.ContentTypes, Name = "ContentTypes" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.ContentTree, Name = "ContentTree" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.MediaTypes, Name = "MediaTypes" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.MediaTree, Name = "MediaTree" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.MemberTypes, Name = "MemberTypes" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.MemberTree, Name = "MemberTree" });
|
||||
_database.Insert("umbracoLock", "id", false, new LockDto { Id = Constants.Locks.Domains, Name = "Domains" });
|
||||
}
|
||||
|
||||
private void CreateCmsContentTypeData()
|
||||
{
|
||||
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = "icon-folder", Thumbnail = "icon-folder", IsContainer = false, AllowAtRoot = true });
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{44, typeof (ExternalLoginDto)},
|
||||
{45, typeof (MigrationDto)},
|
||||
{46, typeof (UmbracoDeployChecksumDto)},
|
||||
{47, typeof (UmbracoDeployDependencyDto)}
|
||||
{47, typeof (UmbracoDeployDependencyDto)},
|
||||
{48, typeof (LockDto) }
|
||||
};
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionEight
|
||||
{
|
||||
[Migration("8.0.0", 101, GlobalSettings.UmbracoMigrationName)]
|
||||
public class AddLockObjects : MigrationBase
|
||||
{
|
||||
public AddLockObjects(ILogger logger)
|
||||
: base(logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
// some may already exist, just ensure everything we need is here
|
||||
EnsureLockObject(Constants.Locks.Servers, "Servers");
|
||||
EnsureLockObject(Constants.Locks.ContentTypes, "ContentTypes");
|
||||
EnsureLockObject(Constants.Locks.ContentTree, "ContentTree");
|
||||
EnsureLockObject(Constants.Locks.MediaTree, "MediaTree");
|
||||
EnsureLockObject(Constants.Locks.MemberTree, "MemberTree");
|
||||
EnsureLockObject(Constants.Locks.MediaTypes, "MediaTypes");
|
||||
EnsureLockObject(Constants.Locks.MemberTypes, "MemberTypes");
|
||||
EnsureLockObject(Constants.Locks.Domains, "Domains");
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
|
||||
private void EnsureLockObject(int id, string name)
|
||||
{
|
||||
Execute.Code(db =>
|
||||
{
|
||||
var exists = db.Exists<LockDto>(id);
|
||||
if (exists) return string.Empty;
|
||||
// be safe: delete old umbracoNode lock objects if any
|
||||
db.Execute($"DELETE FROM umbracoNode WHERE id={id};");
|
||||
// then create umbracoLock object
|
||||
db.Execute($"INSERT umbracoLock (id, name, value) VALUES ({id}, '{name}', 1);");
|
||||
return string.Empty;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionEight
|
||||
{
|
||||
[Migration("8.0.0", 100, GlobalSettings.UmbracoMigrationName)]
|
||||
public class AddLockTable : MigrationBase
|
||||
{
|
||||
public AddLockTable(ILogger logger)
|
||||
: base(logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
|
||||
if (tables.InvariantContains("umbracoLock") == false)
|
||||
{
|
||||
Create.Table("umbracoLock")
|
||||
.WithColumn("id").AsInt32().PrimaryKey("PK_umbracoLock")
|
||||
.WithColumn("value").AsInt32().NotNullable()
|
||||
.WithColumn("name").AsString(64).NotNullable();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
|
||||
Create.Column("isMaster").OnTable("umbracoServer").AsBoolean().NotNullable().WithDefaultValue(0);
|
||||
}
|
||||
|
||||
EnsureLockObject(Constants.System.ServersLock, "0AF5E610-A310-4B6F-925F-E928D5416AF7", "LOCK: Servers");
|
||||
EnsureLockObject(Constants.Locks.Servers, "0AF5E610-A310-4B6F-925F-E928D5416AF7", "LOCK: Servers");
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
|
||||
sortOrder = 0,
|
||||
uniqueId = new Guid(uniqueId),
|
||||
text = text,
|
||||
nodeObjectType = new Guid(Constants.ObjectTypes.LockObject),
|
||||
nodeObjectType = Constants.ObjectTypes.LockObjectGuid,
|
||||
createDate = DateTime.Now
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using StackExchange.Profiling.Helpers.Dapper;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -30,7 +22,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IContent"/>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IContent"/>.
|
||||
/// </summary>
|
||||
internal class ContentRepository : RecycleBinRepository<int, IContent>, IContentRepository
|
||||
{
|
||||
@@ -44,9 +36,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public ContentRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, IContentSection contentSection, IMappingResolver mappingResolver)
|
||||
: base(work, cacheHelper, logger, contentSection, mappingResolver)
|
||||
{
|
||||
if (contentTypeRepository == null) throw new ArgumentNullException("contentTypeRepository");
|
||||
if (templateRepository == null) throw new ArgumentNullException("templateRepository");
|
||||
if (tagRepository == null) throw new ArgumentNullException("tagRepository");
|
||||
if (contentTypeRepository == null) throw new ArgumentNullException(nameof(contentTypeRepository));
|
||||
if (templateRepository == null) throw new ArgumentNullException(nameof(templateRepository));
|
||||
if (tagRepository == null) throw new ArgumentNullException(nameof(tagRepository));
|
||||
_contentTypeRepository = contentTypeRepository;
|
||||
_templateRepository = templateRepository;
|
||||
_tagRepository = tagRepository;
|
||||
@@ -73,7 +65,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateContentFromDto(dto, dto.ContentVersionDto.VersionId, sql);
|
||||
var content = CreateContentFromDto(dto, dto.ContentVersionDto.VersionId);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -83,7 +75,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
if (ids.Any())
|
||||
{
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
sql.Where("umbracoNode.id in (@ids)", new { /*ids =*/ ids });
|
||||
}
|
||||
|
||||
//we only want the newest ones with this method
|
||||
@@ -98,7 +90,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
|
||||
//.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
|
||||
.OrderBy<NodeDto>(x => x.Level)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return MapQueryDtos(Database.Fetch<DocumentDto>(sql));
|
||||
@@ -173,100 +166,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return list;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.Document); }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => new Guid(Constants.ObjectTypes.Document);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of VersionableRepositoryBase<IContent>
|
||||
|
||||
public void RebuildXmlStructures(Func<IContent, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = Database.GetTransaction())
|
||||
{
|
||||
//Remove all the data first, if anything fails after this it's no problem the transaction will be reverted
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<DocumentDto>()
|
||||
.On<ContentXmlDto, DocumentDto>(left => left.NodeId, right => right.NodeId);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in contentTypeIds)
|
||||
{
|
||||
var id1 = id;
|
||||
var subQuery = Sql()
|
||||
.Select("cmsDocument.nodeId")
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<DocumentDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<DocumentDto>(dto => dto.Published)
|
||||
.Where<ContentDto>( dto => dto.ContentTypeId == id1);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
}
|
||||
|
||||
//now insert the data, again if something fails here, the whole transaction is reversed
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var query = Query.Where(x => x.Published == true);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
{
|
||||
//copy local
|
||||
var id = contentTypeId;
|
||||
var query = Query.Where(x => x.Published == true && x.ContentTypeId == id && x.Trashed == false);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
}
|
||||
|
||||
tr.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildXmlStructuresProcessQuery(Func<IContent, XElement> serializer, IQuery<IContent> query, ITransaction tr, int pageSize)
|
||||
{
|
||||
var pageIndex = 0;
|
||||
var total = long.MinValue;
|
||||
var processed = 0;
|
||||
do
|
||||
{
|
||||
//NOTE: This is an important call, we cannot simply make a call to:
|
||||
// GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending);
|
||||
// because that method is used to query 'latest' content items where in this case we don't necessarily
|
||||
// want latest content items because a pulished content item might not actually be the latest.
|
||||
// see: http://issues.umbraco.org/issue/U4-6322 & http://issues.umbraco.org/issue/U4-5982
|
||||
var descendants = GetPagedResultsByQuery<DocumentDto>(query, pageIndex, pageSize, out total,
|
||||
MapQueryDtos, "Path", Direction.Ascending, true);
|
||||
|
||||
var xmlItems = (from descendant in descendants
|
||||
let xml = serializer(descendant)
|
||||
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
|
||||
|
||||
//bulk insert it into the database
|
||||
Database.BulkInsertRecords(SqlSyntax, xmlItems, tr);
|
||||
|
||||
processed += xmlItems.Length;
|
||||
|
||||
pageIndex++;
|
||||
} while (processed < total);
|
||||
}
|
||||
|
||||
public override IContent GetByVersion(Guid versionId)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
@@ -278,7 +183,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateContentFromDto(dto, versionId, sql);
|
||||
var content = CreateContentFromDto(dto, versionId);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -360,9 +265,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//ensure the default template is assigned
|
||||
if (entity.Template == null)
|
||||
{
|
||||
entity.Template = entity.ContentType.DefaultTemplate;
|
||||
}
|
||||
|
||||
//Ensure unique name on the same level
|
||||
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
|
||||
@@ -375,10 +278,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//NOTE Should the logic below have some kind of fallback for empty parent ids ?
|
||||
//Logic for setting Path, Level and SortOrder
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { /*ParentId =*/ entity.ParentId });
|
||||
var level = parent.Level + 1;
|
||||
var maxSortOrder = Database.ExecuteScalar<int>(
|
||||
"SELECT coalesce(max(sortOrder),-1) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
"SELECT coalesce(max(sortOrder),-1) FROM umbracoNode WHERE parentId = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { /*ParentId =*/ entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
var sortOrder = maxSortOrder + 1;
|
||||
|
||||
@@ -387,7 +290,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
var o = Database.IsNew<NodeDto>(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
@@ -401,6 +304,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//Assign the same permissions to it as the parent node
|
||||
// http://issues.umbraco.org/issue/U4-2161
|
||||
// fixme STOP new-ing repos everywhere!
|
||||
// var prepo = UnitOfWork.CreateRepository<IPermissionRepository<IContent>>();
|
||||
var permissionsRepo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
|
||||
var parentPermissions = permissionsRepo.GetPermissionsForEntity(entity.ParentId).ToArray();
|
||||
//if there are parent permissions then assign them, otherwise leave null and permissions will become the
|
||||
@@ -448,15 +353,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//Update Properties with its newly set Id
|
||||
foreach (var property in entity.Properties)
|
||||
{
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
|
||||
//lastly, check if we are a creating a published version , then update the tags table
|
||||
if (entity.Published)
|
||||
{
|
||||
UpdatePropertyTags(entity, _tagRepository);
|
||||
}
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
|
||||
// published => update published version infos, else leave it blank
|
||||
if (entity.Published)
|
||||
@@ -476,7 +377,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override void PersistUpdatedItem(IContent entity)
|
||||
{
|
||||
var publishedState = ((Content)entity).PublishedState;
|
||||
var content = (Content) entity;
|
||||
var publishedState = content.PublishedState;
|
||||
var publishedStateChanged = publishedState == PublishedState.Publishing || publishedState == PublishedState.Unpublishing;
|
||||
|
||||
//check if we need to make any database changes at all
|
||||
if (entity.RequiresSaving(publishedState) == false)
|
||||
@@ -486,11 +389,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
//check if we need to create a new version
|
||||
bool shouldCreateNewVersion = entity.ShouldCreateNewVersion(publishedState);
|
||||
if (shouldCreateNewVersion)
|
||||
var requiresNewVersion = entity.RequiresNewVersion(publishedState);
|
||||
if (requiresNewVersion)
|
||||
{
|
||||
//Updates Modified date and Version Guid
|
||||
((Content)entity).UpdatingEntity();
|
||||
content.UpdatingEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -506,14 +409,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
|
||||
if (entity.IsPropertyDirty("ParentId"))
|
||||
{
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { /*ParentId =*/ entity.ParentId });
|
||||
entity.Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
entity.Level = parent.Level + 1;
|
||||
var maxSortOrder =
|
||||
Database.ExecuteScalar<int>(
|
||||
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
entity.SortOrder = maxSortOrder + 1;
|
||||
entity.SortOrder = NextChildSortOrder(entity.ParentId);
|
||||
|
||||
//Question: If we move a node, should we update permissions to inherit from the new parent if the parent has permissions assigned?
|
||||
// if we do that, then we'd need to propogate permissions all the way downward which might not be ideal for many people.
|
||||
@@ -522,7 +421,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var factory = new ContentFactory(NodeObjectTypeId, entity.Id);
|
||||
//Look up Content entry to get Primary for updating the DTO
|
||||
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { /*Id =*/ entity.Id });
|
||||
factory.SetPrimaryKey(contentDto.PrimaryKey);
|
||||
var dto = factory.BuildDto(entity);
|
||||
|
||||
@@ -538,37 +437,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Update(newContentDto);
|
||||
}
|
||||
|
||||
//a flag that we'll use later to create the tags in the tag db table
|
||||
var publishedStateChanged = false;
|
||||
|
||||
//If Published state has changed then previous versions should have their publish state reset.
|
||||
//If state has been changed to unpublished the previous versions publish state should also be reset.
|
||||
//if (((ICanBeDirty)entity).IsPropertyDirty("Published") && (entity.Published || publishedState == PublishedState.Unpublished))
|
||||
if (entity.ShouldClearPublishedFlagForPreviousVersions(publishedState, shouldCreateNewVersion))
|
||||
{
|
||||
var publishedDocs = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND published = @IsPublished", new { Id = entity.Id, IsPublished = true });
|
||||
foreach (var doc in publishedDocs)
|
||||
{
|
||||
var docDto = doc;
|
||||
docDto.Published = false;
|
||||
Database.Update(docDto);
|
||||
}
|
||||
|
||||
//this is a newly published version so we'll update the tags table too (end of this method)
|
||||
publishedStateChanged = true;
|
||||
}
|
||||
if (entity.RequiresClearPublishedFlag(publishedState, requiresNewVersion))
|
||||
ClearPublishedFlag(entity);
|
||||
|
||||
//Look up (newest) entries by id in cmsDocument table to set newest = false
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
|
||||
foreach (var documentDto in documentDtos)
|
||||
{
|
||||
var docDto = documentDto;
|
||||
docDto.Newest = false;
|
||||
Database.Update(docDto);
|
||||
}
|
||||
ClearNewestFlag(entity);
|
||||
|
||||
var contentVersionDto = dto.ContentVersionDto;
|
||||
if (shouldCreateNewVersion)
|
||||
if (requiresNewVersion)
|
||||
{
|
||||
//Create a new version - cmsContentVersion
|
||||
//Assumes a new Version guid and Version date (modified date) has been set
|
||||
@@ -580,7 +459,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
else
|
||||
{
|
||||
//In order to update the ContentVersion we need to retrieve its primary key id
|
||||
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { Version = entity.Version });
|
||||
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { /*Version =*/ entity.Version });
|
||||
contentVersionDto.Id = contentVerDto.Id;
|
||||
|
||||
Database.Update(contentVersionDto);
|
||||
@@ -595,7 +474,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Add Properties
|
||||
foreach (var propertyDataDto in propertyDataDtos)
|
||||
{
|
||||
if (shouldCreateNewVersion == false && propertyDataDto.Id > 0)
|
||||
if (requiresNewVersion == false && propertyDataDto.Id > 0)
|
||||
{
|
||||
Database.Update(propertyDataDto);
|
||||
}
|
||||
@@ -617,19 +496,38 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
//lastly, check if we are a newly published version and then update the tags table
|
||||
if (publishedStateChanged && entity.Published)
|
||||
// tags:
|
||||
if (HasTagProperty(entity))
|
||||
{
|
||||
UpdatePropertyTags(entity, _tagRepository);
|
||||
}
|
||||
else if (publishedStateChanged && (entity.Trashed || entity.Published == false))
|
||||
{
|
||||
//it's in the trash or not published remove all entity tags
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
// if path-published, update tags, else clear tags
|
||||
switch (content.PublishedState)
|
||||
{
|
||||
case PublishedState.Publishing:
|
||||
// explicitely publishing, must update tags
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
break;
|
||||
case PublishedState.Unpublishing:
|
||||
// explicitely unpublishing, must clear tags
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
break;
|
||||
case PublishedState.Saving:
|
||||
// saving, nothing to do
|
||||
break;
|
||||
case PublishedState.Published:
|
||||
case PublishedState.Unpublished:
|
||||
// no change, depends on path-published
|
||||
// that should take care of trashing and un-trashing
|
||||
if (IsPathPublished(entity)) // slightly expensive ;-(
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
else
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// published => update published version infos,
|
||||
// else if unpublished then clear published version infos
|
||||
// else leave unchanged
|
||||
if (entity.Published)
|
||||
{
|
||||
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
|
||||
@@ -639,7 +537,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
NodeId = dto.NodeId,
|
||||
Published = true
|
||||
};
|
||||
((Content)entity).PublishedVersionGuid = dto.VersionId;
|
||||
content.PublishedVersionGuid = dto.VersionId;
|
||||
}
|
||||
else if (publishedStateChanged)
|
||||
{
|
||||
@@ -650,12 +548,20 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
NodeId = dto.NodeId,
|
||||
Published = false
|
||||
};
|
||||
((Content)entity).PublishedVersionGuid = default(Guid);
|
||||
content.PublishedVersionGuid = default(Guid);
|
||||
}
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
private int NextChildSortOrder(int parentId)
|
||||
{
|
||||
var maxSortOrder =
|
||||
Database.ExecuteScalar<int>(
|
||||
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = parentId, NodeObjectType = NodeObjectTypeId });
|
||||
return maxSortOrder + 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -664,9 +570,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public IEnumerable<IContent> GetByPublishedVersion(IQuery<IContent> query)
|
||||
{
|
||||
// we WANT to return contents in top-down order, ie parents should come before children
|
||||
// ideal would be pure xml "document order" which can be achieved with:
|
||||
// ORDER BY substring(path, 1, len(path) - charindex(',', reverse(path))), sortOrder
|
||||
// but that's probably an overkill - sorting by level,sortOrder should be enough
|
||||
// ideal would be pure xml "document order" - which we cannot achieve at database level
|
||||
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
@@ -680,27 +584,42 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
//Check in the cache first. If it exists there AND it is published
|
||||
// then we can use that entity. Otherwise if it is not published (which can be the case
|
||||
// because we only store the 'latest' entries in the cache which might not be the published
|
||||
// version)
|
||||
// check cache first, if it exists and is published, use it
|
||||
// it may exist and not be published as the cache has 'latest version used'
|
||||
var fromCache = RuntimeCache.GetCacheItem<IContent>(GetCacheIdKey<IContent>(dto.NodeId));
|
||||
//var fromCache = TryGetFromCache(dto.NodeId);
|
||||
if (fromCache != null && fromCache.Published)
|
||||
{
|
||||
yield return fromCache;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return CreateContentFromDto(dto, dto.VersionId, sql);
|
||||
}
|
||||
yield return fromCache != null && fromCache.Published
|
||||
? fromCache
|
||||
: CreateContentFromDto(dto, dto.VersionId);
|
||||
}
|
||||
}
|
||||
|
||||
public int CountPublished()
|
||||
public int CountPublished(string contentTypeAlias = null)
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
var sql = Sql();
|
||||
if (contentTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
sql.SelectCount()
|
||||
.From<NodeDto>()
|
||||
.InnerJoin<DocumentDto>()
|
||||
.On<NodeDto, DocumentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId && x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.SelectCount()
|
||||
.From<NodeDto>()
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<NodeDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<DocumentDto>()
|
||||
.On<NodeDto, DocumentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentTypeDto>()
|
||||
.On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId && x.Trashed == false)
|
||||
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias)
|
||||
.Where<DocumentDto>(x => x.Published);
|
||||
}
|
||||
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
|
||||
@@ -710,10 +629,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
repo.ReplaceEntityPermissions(permissionSet);
|
||||
}
|
||||
|
||||
public void ClearPublished(IContent content)
|
||||
public void ClearPublishedFlag(IContent content)
|
||||
{
|
||||
// race cond!
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId=@id AND published=@published", new { id = content.Id, published = true });
|
||||
// no race cond if locked
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId=@Id AND published=@IsPublished", new { /*Id =*/ content.Id, IsPublished = true });
|
||||
foreach (var documentDto in documentDtos)
|
||||
{
|
||||
documentDto.Published = false;
|
||||
@@ -721,6 +640,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearNewestFlag(IContent content)
|
||||
{
|
||||
// no race cond if locked
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId=@Id AND newest=@IsNewest", new { /*Id =*/ content.Id, IsNewest = true });
|
||||
foreach (var documentDto in documentDtos)
|
||||
{
|
||||
documentDto.Newest = false;
|
||||
Database.Update(documentDto);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a single permission to the current content item for the specified user ids
|
||||
/// </summary>
|
||||
@@ -739,35 +669,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return repo.GetPermissionsForEntity(entityId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds/updates content/published xml
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="xml"></param>
|
||||
public void AddOrUpdateContentXml(IContent content, Func<IContent, XElement> xml)
|
||||
{
|
||||
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IContent>(content, xml));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to remove the content xml for a content item
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
public void DeleteContentXml(IContent content)
|
||||
{
|
||||
_contentXmlRepository.Delete(new ContentXmlEntity<IContent>(content));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds/updates preview xml
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="xml"></param>
|
||||
public void AddOrUpdatePreviewXml(IContent content, Func<IContent, XElement> xml)
|
||||
{
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IContent>(content, xml));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged content results
|
||||
/// </summary>
|
||||
@@ -793,42 +694,40 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
filterSql);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the persisted content's preview XML structure
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
/// <returns></returns>
|
||||
public XElement GetContentXml(int contentId)
|
||||
public bool IsPathPublished(IContent content)
|
||||
{
|
||||
var sql = Sql().SelectAll().From<ContentXmlDto>().Where<ContentXmlDto>(d => d.NodeId == contentId);
|
||||
var dto = Database.SingleOrDefault<ContentXmlDto>(sql);
|
||||
if (dto == null) return null;
|
||||
return XElement.Parse(dto.Xml);
|
||||
}
|
||||
// fail fast
|
||||
if (content.Path.StartsWith("-1,-20,"))
|
||||
return false;
|
||||
// succeed fast
|
||||
if (content.ParentId == -1)
|
||||
return content.HasPublishedVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the persisted content's preview XML structure
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
/// <param name="version"></param>
|
||||
/// <returns></returns>
|
||||
public XElement GetContentPreviewXml(int contentId, Guid version)
|
||||
{
|
||||
var sql = Sql().SelectAll().From<PreviewXmlDto>()
|
||||
.Where<PreviewXmlDto>(d => d.NodeId == contentId && d.VersionId == version);
|
||||
var dto = Database.SingleOrDefault<PreviewXmlDto>(sql);
|
||||
if (dto == null) return null;
|
||||
return XElement.Parse(dto.Xml);
|
||||
var syntaxUmbracoNode = SqlSyntax.GetQuotedTableName("umbracoNode");
|
||||
var syntaxPath = SqlSyntax.GetQuotedColumnName("path");
|
||||
var syntaxConcat = SqlSyntax.GetConcat(syntaxUmbracoNode + "." + syntaxPath, "',%'");
|
||||
|
||||
var sql = string.Format(@"SELECT COUNT({0}.{1})
|
||||
FROM {0}
|
||||
JOIN {2} ON ({0}.{1}={2}.{3} AND {2}.{4}=@published)
|
||||
WHERE (@path LIKE {5})",
|
||||
syntaxUmbracoNode,
|
||||
SqlSyntax.GetQuotedColumnName("id"),
|
||||
SqlSyntax.GetQuotedTableName("cmsDocument"),
|
||||
SqlSyntax.GetQuotedColumnName("nodeId"),
|
||||
SqlSyntax.GetQuotedColumnName("published"),
|
||||
syntaxConcat);
|
||||
|
||||
var count = Database.ExecuteScalar<int>(sql, new { @published=true, @path=content.Path });
|
||||
count += 1; // because content does not count
|
||||
return count == content.Level;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IRecycleBinRepository members
|
||||
|
||||
protected override int RecycleBinId
|
||||
{
|
||||
get { return Constants.System.RecycleBinContent; }
|
||||
}
|
||||
protected override int RecycleBinId => Constants.System.RecycleBinContent;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -885,7 +784,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return dtosWithContentTypes.Select(d => CreateContentFromDto(
|
||||
d.dto,
|
||||
contentTypes.First(ct => ct.Id == d.dto.ContentVersionDto.ContentDto.ContentTypeId),
|
||||
templates.FirstOrDefault(tem => tem.Id == (d.dto.TemplateId.HasValue ? d.dto.TemplateId.Value : -1)),
|
||||
templates.FirstOrDefault(tem => tem.Id == (d.dto.TemplateId ?? -1)),
|
||||
propertyData[d.dto.NodeId]));
|
||||
}
|
||||
|
||||
@@ -900,7 +799,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private IContent CreateContentFromDto(DocumentDto dto,
|
||||
IContentType contentType,
|
||||
ITemplate template,
|
||||
Models.PropertyCollection propCollection)
|
||||
PropertyCollection propCollection)
|
||||
{
|
||||
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var content = factory.BuildEntity(dto);
|
||||
@@ -929,9 +828,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId, Sql docSql)
|
||||
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId)
|
||||
{
|
||||
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
|
||||
@@ -979,7 +877,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (dto.Text.ToLowerInvariant().Equals(currentName.ToLowerInvariant()))
|
||||
{
|
||||
currentName = nodeName + string.Format(" ({0})", uniqueNumber);
|
||||
currentName = nodeName + $" ({uniqueNumber})";
|
||||
uniqueNumber++;
|
||||
}
|
||||
}
|
||||
@@ -987,5 +885,151 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return currentName;
|
||||
}
|
||||
|
||||
#region Xml - Should Move!
|
||||
|
||||
public void RebuildXmlStructures(Func<IContent, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = Database.GetTransaction())
|
||||
{
|
||||
//Remove all the data first, if anything fails after this it's no problem the transaction will be reverted
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<DocumentDto>()
|
||||
.On<ContentXmlDto, DocumentDto>(left => left.NodeId, right => right.NodeId);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in contentTypeIds)
|
||||
{
|
||||
var id1 = id;
|
||||
var subQuery = Sql()
|
||||
.Select("cmsDocument.nodeId")
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<DocumentDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<DocumentDto>(dto => dto.Published)
|
||||
.Where<ContentDto>(dto => dto.ContentTypeId == id1);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
}
|
||||
|
||||
//now insert the data, again if something fails here, the whole transaction is reversed
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var query = Query.Where(x => x.Published);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
{
|
||||
//copy local
|
||||
var id = contentTypeId;
|
||||
var query = Query.Where(x => x.Published && x.ContentTypeId == id && x.Trashed == false);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
}
|
||||
|
||||
tr.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildXmlStructuresProcessQuery(Func<IContent, XElement> serializer, IQuery<IContent> query, ITransaction tr, int pageSize)
|
||||
{
|
||||
var pageIndex = 0;
|
||||
long total;
|
||||
var processed = 0;
|
||||
do
|
||||
{
|
||||
//NOTE: This is an important call, we cannot simply make a call to:
|
||||
// GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending);
|
||||
// because that method is used to query 'latest' content items where in this case we don't necessarily
|
||||
// want latest content items because a pulished content item might not actually be the latest.
|
||||
// see: http://issues.umbraco.org/issue/U4-6322 & http://issues.umbraco.org/issue/U4-5982
|
||||
var descendants = GetPagedResultsByQuery<DocumentDto>(query, pageIndex, pageSize, out total,
|
||||
MapQueryDtos, "Path", Direction.Ascending, true);
|
||||
|
||||
var xmlItems = (from descendant in descendants
|
||||
let xml = serializer(descendant)
|
||||
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
|
||||
|
||||
//bulk insert it into the database
|
||||
Database.BulkInsertRecords(SqlSyntax, xmlItems, tr);
|
||||
|
||||
processed += xmlItems.Length;
|
||||
|
||||
pageIndex++;
|
||||
} while (processed < total);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds/updates content/published xml
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="xml"></param>
|
||||
public void AddOrUpdateContentXml(IContent content, Func<IContent, XElement> xml)
|
||||
{
|
||||
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IContent>(content, xml));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to remove the content xml for a content item
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
public void DeleteContentXml(IContent content)
|
||||
{
|
||||
_contentXmlRepository.Delete(new ContentXmlEntity<IContent>(content));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds/updates preview xml
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="xml"></param>
|
||||
public void AddOrUpdatePreviewXml(IContent content, Func<IContent, XElement> xml)
|
||||
{
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IContent>(content, xml));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the persisted content's preview XML structure
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
/// <returns></returns>
|
||||
public XElement GetContentXml(int contentId)
|
||||
{
|
||||
var sql = Sql().SelectAll().From<ContentXmlDto>().Where<ContentXmlDto>(d => d.NodeId == contentId);
|
||||
var dto = Database.SingleOrDefault<ContentXmlDto>(sql);
|
||||
if (dto == null) return null;
|
||||
return XElement.Parse(dto.Xml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the persisted content's preview XML structure
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
/// <param name="version"></param>
|
||||
/// <returns></returns>
|
||||
public XElement GetContentPreviewXml(int contentId, Guid version)
|
||||
{
|
||||
var sql = Sql().SelectAll().From<PreviewXmlDto>()
|
||||
.Where<PreviewXmlDto>(d => d.NodeId == contentId && d.VersionId == version);
|
||||
var dto = Database.SingleOrDefault<PreviewXmlDto>(sql);
|
||||
if (dto == null) return null;
|
||||
return XElement.Parse(dto.Xml);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,21 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IContentType"/>
|
||||
/// </summary>
|
||||
internal class ContentTypeRepository : ContentTypeBaseRepository<IContentType>, IContentTypeRepository
|
||||
internal class ContentTypeRepository : ContentTypeRepositoryBase<IContentType>, IContentTypeRepository
|
||||
{
|
||||
private readonly ITemplateRepository _templateRepository;
|
||||
|
||||
@@ -51,6 +46,23 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IContentType PerformGet(Guid id)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IContentType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetAll(params int[] ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
@@ -63,6 +75,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
// use the underlying GetAll which will force cache all content types
|
||||
return ids.Any() ? GetAll().Where(x => ids.Contains(x.Key)) : GetAll();
|
||||
}
|
||||
protected override IEnumerable<IContentType> PerformGetByQuery(IQuery<IContentType> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
@@ -154,28 +172,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
var list = new List<string>
|
||||
{
|
||||
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsContentTypeAllowedContentType WHERE Id = @Id",
|
||||
"DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @Id",
|
||||
"DELETE FROM cmsContentType2ContentType WHERE parentContentTypeId = @Id",
|
||||
"DELETE FROM cmsContentType2ContentType WHERE childContentTypeId = @Id",
|
||||
"DELETE FROM cmsPropertyType WHERE contentTypeId = @Id",
|
||||
"DELETE FROM cmsPropertyTypeGroup WHERE contenttypeNodeId = @Id",
|
||||
"DELETE FROM cmsDocumentType WHERE contentTypeNodeId = @Id",
|
||||
"DELETE FROM cmsContentType WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
};
|
||||
return list;
|
||||
var l = (List<string>) base.GetDeleteClauses(); // we know it's a list
|
||||
l.Add("DELETE FROM cmsDocumentType WHERE contentTypeNodeId = @Id");
|
||||
l.Add("DELETE FROM cmsContentType WHERE nodeId = @Id");
|
||||
l.Add("DELETE FROM umbracoNode WHERE id = @Id");
|
||||
return l;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.DocumentType); }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => Constants.ObjectTypes.DocumentTypeGuid;
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a content type
|
||||
@@ -290,36 +294,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
protected override IContentType PerformGet(Guid id)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IContentType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1274
-1230
File diff suppressed because it is too large
Load Diff
@@ -103,6 +103,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
// so... we are modifying content types here. the service will trigger Deleted event,
|
||||
// which will propagate to DataTypeCacheRefresher which will clear almost every cache
|
||||
// there is to clear... and in addition facade caches will clear themselves too, so
|
||||
// this is probably safe alghough it looks... weird.
|
||||
//
|
||||
// what IS weird is that a content type is losing a property and we do NOT raise any
|
||||
// content type event... so ppl better listen on the data type events too.
|
||||
|
||||
_contentTypeRepository.AddOrUpdate(contentType);
|
||||
}
|
||||
|
||||
@@ -282,8 +290,6 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId)
|
||||
{
|
||||
var cached = RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(GetPrefixedCacheKey(dataTypeId));
|
||||
@@ -485,8 +491,6 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
private string EnsureUniqueNodeName(string nodeName, int id = 0)
|
||||
{
|
||||
|
||||
|
||||
var sql = Sql()
|
||||
.SelectAll()
|
||||
.From<NodeDto>()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -9,7 +8,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentRepository : IRepositoryVersionable<int, IContent>, IRecycleBinRepository<IContent>, IDeleteMediaFilesRepository
|
||||
public interface IContentRepository : IRepositoryVersionable<int, IContent>, IRecycleBinRepository<IContent>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the count of published items
|
||||
@@ -18,7 +17,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <remarks>
|
||||
/// We require this on the repo because the IQuery{IContent} cannot supply the 'newest' parameter
|
||||
/// </remarks>
|
||||
int CountPublished();
|
||||
int CountPublished(string contentTypeAlias = null);
|
||||
|
||||
bool IsPathPublished(IContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Used to bulk update the permissions set for a content item. This will replace all permissions
|
||||
@@ -31,7 +32,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// Clears the published flag for a content.
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
void ClearPublished(IContent content);
|
||||
void ClearPublishedFlag(IContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all published Content by the specified query
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeCompositionRepository<TEntity> : IRepositoryQueryable<int, TEntity>, IReadRepository<Guid, TEntity>
|
||||
where TEntity : IContentTypeComposition
|
||||
{
|
||||
TEntity Get(string alias);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeRepository : IContentTypeCompositionRepository<IContentType>
|
||||
public interface IContentTypeRepository : IContentTypeRepositoryBase<IContentType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
@@ -21,8 +21,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllPropertyTypeAliases();
|
||||
|
||||
IEnumerable<MoveEventInfo<IContentType>> Move(IContentType toMove, EntityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all content type aliases
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeRepositoryBase<TItem> : IRepositoryQueryable<int, TItem>, IReadRepository<Guid, TItem>
|
||||
where TItem : IContentTypeComposition
|
||||
{
|
||||
TItem Get(string alias);
|
||||
IEnumerable<MoveEventInfo<TItem>> Move(TItem moving, EntityContainer container);
|
||||
IEnumerable<TItem> GetTypesDirectlyComposedOf(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Derives a unique alias from an existing alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The original alias.</param>
|
||||
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
|
||||
/// <remarks>Unique accross all content, media and member types.</remarks>
|
||||
string GetUniqueAlias(string alias);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IMediaTypeRepository : IContentTypeCompositionRepository<IMediaType>
|
||||
public interface IMediaTypeRepository : IContentTypeRepositoryBase<IMediaType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
@@ -13,15 +13,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="query"></param>
|
||||
/// <returns>An enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
|
||||
|
||||
IEnumerable<MoveEventInfo<IMediaType>> Move(IMediaType toMove, EntityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// Derives a unique alias from an existing alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The original alias.</param>
|
||||
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
|
||||
/// <remarks>Unique accross all content, media and member types.</remarks>
|
||||
string GetUniqueAlias(string alias);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IMemberTypeRepository : IContentTypeCompositionRepository<IMemberType>
|
||||
{
|
||||
|
||||
}
|
||||
public interface IMemberTypeRepository : IContentTypeRepositoryBase<IMemberType>
|
||||
{ }
|
||||
}
|
||||
@@ -6,8 +6,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public interface IServerRegistrationRepository : IRepositoryQueryable<int, IServerRegistration>
|
||||
{
|
||||
void DeactiveStaleServers(TimeSpan staleTimeout);
|
||||
|
||||
void ReadLockServers();
|
||||
void WriteLockServers();
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -21,7 +17,6 @@ using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
@@ -38,8 +33,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public MediaRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, IContentSection contentSection, IMappingResolver mappingResolver)
|
||||
: base(work, cache, logger, contentSection, mappingResolver)
|
||||
{
|
||||
if (mediaTypeRepository == null) throw new ArgumentNullException("mediaTypeRepository");
|
||||
if (tagRepository == null) throw new ArgumentNullException("tagRepository");
|
||||
if (mediaTypeRepository == null) throw new ArgumentNullException(nameof(mediaTypeRepository));
|
||||
if (tagRepository == null) throw new ArgumentNullException(nameof(tagRepository));
|
||||
_mediaTypeRepository = mediaTypeRepository;
|
||||
_tagRepository = tagRepository;
|
||||
_contentXmlRepository = new ContentXmlRepository<IMedia>(work, CacheHelper.CreateDisabledCacheHelper(), logger, mappingResolver);
|
||||
@@ -47,7 +42,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
EnsureUniqueNaming = contentSection.EnsureUniqueNaming;
|
||||
}
|
||||
|
||||
public bool EnsureUniqueNaming { get; private set; }
|
||||
public bool EnsureUniqueNaming { get; }
|
||||
|
||||
#region Overrides of RepositoryBase<int,IMedia>
|
||||
|
||||
@@ -62,7 +57,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateMediaFromDto(dto, dto.VersionId, sql);
|
||||
var content = CreateMediaFromDto(dto, dto.VersionId);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -72,7 +67,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
if (ids.Any())
|
||||
{
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
sql.Where("umbracoNode.id in (@ids)", new { /*ids =*/ ids });
|
||||
}
|
||||
|
||||
return ProcessQuery(sql);
|
||||
@@ -139,10 +134,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return list;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.Media); }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => new Guid(Constants.ObjectTypes.Media);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -174,94 +166,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return media;
|
||||
}
|
||||
|
||||
public void RebuildXmlStructures(Func<IMedia, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = Database.GetTransaction())
|
||||
{
|
||||
//Remove all the data first, if anything fails after this it's no problem the transaction will be reverted
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in contentTypeIds)
|
||||
{
|
||||
var id1 = id;
|
||||
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType)
|
||||
.Where<ContentDto>(dto => dto.ContentTypeId == id1);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
}
|
||||
|
||||
//now insert the data, again if something fails here, the whole transaction is reversed
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
RebuildXmlStructuresProcessQuery(serializer, Query, tr, groupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
{
|
||||
//copy local
|
||||
var id = contentTypeId;
|
||||
var query = Query.Where(x => x.ContentTypeId == id && x.Trashed == false);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
}
|
||||
|
||||
tr.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildXmlStructuresProcessQuery(Func<IMedia, XElement> serializer, IQuery<IMedia> query, ITransaction tr, int pageSize)
|
||||
{
|
||||
var pageIndex = 0;
|
||||
var total = long.MinValue;
|
||||
var processed = 0;
|
||||
do
|
||||
{
|
||||
var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending, true);
|
||||
|
||||
var xmlItems = (from descendant in descendants
|
||||
let xml = serializer(descendant)
|
||||
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
|
||||
|
||||
//bulk insert it into the database
|
||||
Database.BulkInsertRecords(SqlSyntax, xmlItems, tr);
|
||||
|
||||
processed += xmlItems.Length;
|
||||
|
||||
pageIndex++;
|
||||
} while (processed < total);
|
||||
}
|
||||
|
||||
public IMedia GetMediaByPath(string mediaPath)
|
||||
{
|
||||
var umbracoFileValue = mediaPath;
|
||||
const string Pattern = ".*[_][0-9]+[x][0-9]+[.].*";
|
||||
var isResized = Regex.IsMatch(mediaPath, Pattern);
|
||||
const string pattern = ".*[_][0-9]+[x][0-9]+[.].*";
|
||||
var isResized = Regex.IsMatch(mediaPath, pattern);
|
||||
|
||||
// If the image has been resized we strip the "_403x328" of the original "/media/1024/koala_403x328.jpg" url.
|
||||
if (isResized)
|
||||
@@ -292,17 +201,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return propertyDataDto == null ? null : Get(propertyDataDto.NodeId);
|
||||
}
|
||||
|
||||
public void AddOrUpdateContentXml(IMedia content, Func<IMedia, XElement> xml)
|
||||
{
|
||||
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IMedia>(content, xml));
|
||||
}
|
||||
|
||||
public void AddOrUpdatePreviewXml(IMedia content, Func<IMedia, XElement> xml)
|
||||
{
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IMedia>(content, xml));
|
||||
}
|
||||
|
||||
protected override void PerformDeleteVersion(int id, Guid versionId)
|
||||
{
|
||||
Database.Delete<PreviewXmlDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
@@ -329,10 +227,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//NOTE Should the logic below have some kind of fallback for empty parent ids ?
|
||||
//Logic for setting Path, Level and SortOrder
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { /*ParentId =*/ entity.ParentId });
|
||||
var level = parent.Level + 1;
|
||||
var maxSortOrder = Database.ExecuteScalar<int>(
|
||||
"SELECT coalesce(max(sortOrder),-1) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
"SELECT coalesce(max(sortOrder),-1) FROM umbracoNode WHERE parentId = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { /*ParentId =*/ entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
var sortOrder = maxSortOrder + 1;
|
||||
|
||||
@@ -341,7 +239,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
var o = Database.IsNew<NodeDto>(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
@@ -381,7 +279,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
|
||||
UpdatePropertyTags(entity, _tagRepository);
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
@@ -400,19 +298,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
|
||||
if (entity.IsPropertyDirty("ParentId"))
|
||||
{
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { /*ParentId =*/ entity.ParentId });
|
||||
entity.Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
entity.Level = parent.Level + 1;
|
||||
var maxSortOrder =
|
||||
Database.ExecuteScalar<int>(
|
||||
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
new { /*ParentId =*/ entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
entity.SortOrder = maxSortOrder + 1;
|
||||
}
|
||||
|
||||
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
|
||||
//Look up Content entry to get Primary for updating the DTO
|
||||
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { /*Id =*/ entity.Id });
|
||||
factory.SetPrimaryKey(contentDto.PrimaryKey);
|
||||
var dto = factory.BuildDto(entity);
|
||||
|
||||
@@ -429,7 +327,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
//In order to update the ContentVersion we need to retrieve its primary key id
|
||||
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { Version = entity.Version });
|
||||
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { /*Version =*/ entity.Version });
|
||||
dto.Id = contentVerDto.Id;
|
||||
//Updates the current version - cmsContentVersion
|
||||
//Assumes a Version guid exists and Version date (modified date) has been set/updated
|
||||
@@ -463,7 +361,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePropertyTags(entity, _tagRepository);
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
@@ -472,10 +370,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region IRecycleBinRepository members
|
||||
|
||||
protected override int RecycleBinId
|
||||
{
|
||||
get { return Constants.System.RecycleBinMedia; }
|
||||
}
|
||||
protected override int RecycleBinId => Constants.System.RecycleBinMedia;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -544,7 +439,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="propCollection"></param>
|
||||
/// <returns></returns>
|
||||
@@ -566,11 +461,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId, Sql docSql)
|
||||
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId)
|
||||
{
|
||||
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
|
||||
@@ -612,7 +506,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (dto.Text.ToLowerInvariant().Equals(currentName.ToLowerInvariant()))
|
||||
{
|
||||
currentName = nodeName + string.Format(" ({0})", uniqueNumber);
|
||||
currentName = $"{nodeName} ({uniqueNumber})";
|
||||
uniqueNumber++;
|
||||
}
|
||||
}
|
||||
@@ -620,5 +514,103 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return currentName;
|
||||
}
|
||||
|
||||
#region Xml - Should Move!
|
||||
|
||||
public void RebuildXmlStructures(Func<IMedia, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = Database.GetTransaction())
|
||||
{
|
||||
//Remove all the data first, if anything fails after this it's no problem the transaction will be reverted
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in contentTypeIds)
|
||||
{
|
||||
var id1 = id;
|
||||
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType)
|
||||
.Where<ContentDto>(dto => dto.ContentTypeId == id1);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
}
|
||||
|
||||
//now insert the data, again if something fails here, the whole transaction is reversed
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
RebuildXmlStructuresProcessQuery(serializer, Query, tr, groupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
{
|
||||
//copy local
|
||||
var id = contentTypeId;
|
||||
var query = Query.Where(x => x.ContentTypeId == id && x.Trashed == false);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
}
|
||||
|
||||
tr.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildXmlStructuresProcessQuery(Func<IMedia, XElement> serializer, IQuery<IMedia> query, ITransaction tr, int pageSize)
|
||||
{
|
||||
var pageIndex = 0;
|
||||
long total;
|
||||
var processed = 0;
|
||||
do
|
||||
{
|
||||
var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending, true);
|
||||
|
||||
var xmlItems = (from descendant in descendants
|
||||
let xml = serializer(descendant)
|
||||
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
|
||||
|
||||
//bulk insert it into the database
|
||||
Database.BulkInsertRecords(SqlSyntax, xmlItems, tr);
|
||||
|
||||
processed += xmlItems.Length;
|
||||
|
||||
pageIndex++;
|
||||
} while (processed < total);
|
||||
}
|
||||
|
||||
|
||||
public void AddOrUpdateContentXml(IMedia content, Func<IMedia, XElement> xml)
|
||||
{
|
||||
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IMedia>(content, xml));
|
||||
}
|
||||
|
||||
public void AddOrUpdatePreviewXml(IMedia content, Func<IMedia, XElement> xml)
|
||||
{
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IMedia>(content, xml));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,32 +3,23 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IMediaType"/>
|
||||
/// </summary>
|
||||
internal class MediaTypeRepository : ContentTypeBaseRepository<IMediaType>, IMediaTypeRepository
|
||||
internal class MediaTypeRepository : ContentTypeRepositoryBase<IMediaType>, IMediaTypeRepository
|
||||
{
|
||||
|
||||
public MediaTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMappingResolver mappingResolver)
|
||||
: base(work, cache, logger, mappingResolver)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
private FullDataSetRepositoryCachePolicyFactory<IMediaType, int> _cachePolicyFactory;
|
||||
protected override IRepositoryCachePolicyFactory<IMediaType, int> CachePolicyFactory
|
||||
@@ -49,6 +40,23 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(Guid id)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetAll(params int[] ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
@@ -61,6 +69,20 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetByQuery(IQuery<IMediaType> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
@@ -82,7 +104,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns>An enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IMediaType"/> objects</returns>
|
||||
public IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query)
|
||||
{
|
||||
var ints = PerformGetByQuery(query).ToArray();
|
||||
@@ -116,28 +138,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
var list = new List<string>
|
||||
{
|
||||
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsContentTypeAllowedContentType WHERE Id = @Id",
|
||||
"DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @Id",
|
||||
"DELETE FROM cmsContentType2ContentType WHERE parentContentTypeId = @Id",
|
||||
"DELETE FROM cmsContentType2ContentType WHERE childContentTypeId = @Id",
|
||||
"DELETE FROM cmsPropertyType WHERE contentTypeId = @Id",
|
||||
"DELETE FROM cmsPropertyTypeGroup WHERE contenttypeNodeId = @Id",
|
||||
"DELETE FROM cmsContentType WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
};
|
||||
return list;
|
||||
var l = (List<string>) base.GetDeleteClauses(); // we know it's a list
|
||||
l.Add("DELETE FROM cmsContentType WHERE nodeId = @Id");
|
||||
l.Add("DELETE FROM umbracoNode WHERE id = @Id");
|
||||
return l;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.MediaType); }
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId => Constants.ObjectTypes.MediaTypeGuid;
|
||||
|
||||
protected override void PersistNewItem(IMediaType entity)
|
||||
{
|
||||
((MediaType)entity).AddingEntity();
|
||||
@@ -171,36 +179,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(Guid id)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -19,7 +15,6 @@ using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -38,8 +33,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public MemberRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, IContentSection contentSection, IMappingResolver mappingResolver)
|
||||
: base(work, cache, logger, contentSection, mappingResolver)
|
||||
{
|
||||
if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
|
||||
if (tagRepository == null) throw new ArgumentNullException("tagRepository");
|
||||
if (memberTypeRepository == null) throw new ArgumentNullException(nameof(memberTypeRepository));
|
||||
if (tagRepository == null) throw new ArgumentNullException(nameof(tagRepository));
|
||||
_memberTypeRepository = memberTypeRepository;
|
||||
_tagRepository = tagRepository;
|
||||
_memberGroupRepository = memberGroupRepository;
|
||||
@@ -60,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateMemberFromDto(dto, dto.ContentVersionDto.VersionId, sql);
|
||||
var content = CreateMemberFromDto(dto, dto.ContentVersionDto.VersionId);
|
||||
|
||||
return content;
|
||||
|
||||
@@ -71,7 +66,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
if (ids.Any())
|
||||
{
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
sql.Where("umbracoNode.id in (@ids)", new { /*ids =*/ ids });
|
||||
}
|
||||
|
||||
return MapQueryDtos(Database.Fetch<MemberDto>(sql));
|
||||
@@ -117,8 +112,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = Sql();
|
||||
|
||||
sql = isCount
|
||||
? sql.SelectCount()
|
||||
sql = isCount
|
||||
? sql.SelectCount()
|
||||
: sql.Select<MemberDto>(r =>
|
||||
r.Select<ContentVersionDto>(rr =>
|
||||
rr.Select<ContentDto>(rrr =>
|
||||
@@ -184,10 +179,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return list;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.Member); }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => new Guid(Constants.ObjectTypes.Member);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -205,18 +197,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//NOTE Should the logic below have some kind of fallback for empty parent ids ?
|
||||
//Logic for setting Path, Level and SortOrder
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = ((IUmbracoEntity)entity).ParentId });
|
||||
int level = parent.Level + 1;
|
||||
int sortOrder =
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { /*ParentId =*/ entity.ParentId });
|
||||
var level = parent.Level + 1;
|
||||
var sortOrder =
|
||||
Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoNode WHERE parentID = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = ((IUmbracoEntity)entity).ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
new { /*ParentId =*/ entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
|
||||
//Create the (base) node data - umbracoNode
|
||||
var nodeDto = dto.ContentVersionDto.ContentDto.NodeDto;
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
var o = Database.IsNew<NodeDto>(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
@@ -265,7 +257,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
|
||||
UpdatePropertyTags(entity, _tagRepository);
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
|
||||
((Member)entity).ResetDirtyProperties();
|
||||
}
|
||||
@@ -283,19 +275,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
|
||||
if (dirtyEntity.IsPropertyDirty("ParentId"))
|
||||
{
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = ((IUmbracoEntity)entity).ParentId });
|
||||
((IUmbracoEntity)entity).Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
((IUmbracoEntity)entity).Level = parent.Level + 1;
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { /*ParentId =*/ entity.ParentId });
|
||||
entity.Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
entity.Level = parent.Level + 1;
|
||||
var maxSortOrder =
|
||||
Database.ExecuteScalar<int>(
|
||||
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = ((IUmbracoEntity)entity).ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
((IUmbracoEntity)entity).SortOrder = maxSortOrder + 1;
|
||||
new { /*ParentId =*/ entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
entity.SortOrder = maxSortOrder + 1;
|
||||
}
|
||||
|
||||
var factory = new MemberFactory(NodeObjectTypeId, entity.Id);
|
||||
//Look up Content entry to get Primary for updating the DTO
|
||||
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { /*Id =*/ entity.Id });
|
||||
factory.SetPrimaryKey(contentDto.PrimaryKey);
|
||||
var dto = factory.BuildDto(entity);
|
||||
|
||||
@@ -312,7 +304,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
//In order to update the ContentVersion we need to retrieve its primary key id
|
||||
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { Version = entity.Version });
|
||||
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { /*Version =*/ entity.Version });
|
||||
dto.ContentVersionDto.Id = contentVerDto.Id;
|
||||
//Updates the current version - cmsContentVersion
|
||||
//Assumes a Version guid exists and Version date (modified date) has been set/updated
|
||||
@@ -378,7 +370,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePropertyTags(entity, _tagRepository);
|
||||
UpdateEntityTags(entity, _tagRepository);
|
||||
|
||||
dirtyEntity.ResetDirtyProperties();
|
||||
}
|
||||
@@ -387,90 +379,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Overrides of VersionableRepositoryBase<IMembershipUser>
|
||||
|
||||
public void RebuildXmlStructures(Func<IMember, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = Database.GetTransaction())
|
||||
{
|
||||
//Remove all the data first, if anything fails after this it's no problem the transaction will be reverted
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in contentTypeIds)
|
||||
{
|
||||
var id1 = id;
|
||||
var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType)
|
||||
.Where<ContentDto>( dto => dto.ContentTypeId == id1);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
}
|
||||
|
||||
//now insert the data, again if something fails here, the whole transaction is reversed
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var query = Query;
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
{
|
||||
//copy local
|
||||
var id = contentTypeId;
|
||||
var query = Query.Where(x => x.ContentTypeId == id && x.Trashed == false);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
}
|
||||
|
||||
tr.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildXmlStructuresProcessQuery(Func<IMember, XElement> serializer, IQuery<IMember> query, ITransaction tr, int pageSize)
|
||||
{
|
||||
var pageIndex = 0;
|
||||
var total = long.MinValue;
|
||||
var processed = 0;
|
||||
do
|
||||
{
|
||||
var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending, true);
|
||||
|
||||
var xmlItems = (from descendant in descendants
|
||||
let xml = serializer(descendant)
|
||||
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
|
||||
|
||||
//bulk insert it into the database
|
||||
Database.BulkInsertRecords(SqlSyntax, xmlItems, tr);
|
||||
|
||||
processed += xmlItems.Length;
|
||||
|
||||
pageIndex++;
|
||||
} while (processed < total);
|
||||
}
|
||||
|
||||
public override IMember GetByVersion(Guid versionId)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
@@ -534,7 +442,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
query.Where(member => member.Username.SqlWildcard(usernameToMatch, TextColumnType.NVarchar));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
throw new ArgumentOutOfRangeException(nameof(matchType));
|
||||
}
|
||||
var matchedMembers = GetByQuery(query).ToArray();
|
||||
|
||||
@@ -635,16 +543,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
filterSql);
|
||||
}
|
||||
|
||||
public void AddOrUpdateContentXml(IMember content, Func<IMember, XElement> xml)
|
||||
{
|
||||
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IMember>(content, xml));
|
||||
}
|
||||
|
||||
public void AddOrUpdatePreviewXml(IMember content, Func<IMember, XElement> xml)
|
||||
{
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IMember>(content, xml));
|
||||
}
|
||||
|
||||
protected override string GetDatabaseFieldNameForOrderBy(string orderBy)
|
||||
{
|
||||
//Some custom ones
|
||||
@@ -716,9 +614,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
private IMember CreateMemberFromDto(MemberDto dto, Guid versionId, Sql docSql)
|
||||
private IMember CreateMemberFromDto(MemberDto dto, Guid versionId)
|
||||
{
|
||||
var memberType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
|
||||
@@ -736,5 +633,103 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
((Entity)member).ResetDirtyProperties(false);
|
||||
return member;
|
||||
}
|
||||
|
||||
#region Xml - Should Move!
|
||||
|
||||
public void AddOrUpdateContentXml(IMember content, Func<IMember, XElement> xml)
|
||||
{
|
||||
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IMember>(content, xml));
|
||||
}
|
||||
|
||||
public void AddOrUpdatePreviewXml(IMember content, Func<IMember, XElement> xml)
|
||||
{
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IMember>(content, xml));
|
||||
}
|
||||
|
||||
public void RebuildXmlStructures(Func<IMember, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = Database.GetTransaction())
|
||||
{
|
||||
//Remove all the data first, if anything fails after this it's no problem the transaction will be reverted
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in contentTypeIds)
|
||||
{
|
||||
var id1 = id;
|
||||
var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
|
||||
var subQuery = Sql()
|
||||
.Select("DISTINCT cmsContentXml.nodeId")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType)
|
||||
.Where<ContentDto>(dto => dto.ContentTypeId == id1);
|
||||
|
||||
var deleteSql = SqlSyntax.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
|
||||
Database.Execute(deleteSql);
|
||||
}
|
||||
}
|
||||
|
||||
//now insert the data, again if something fails here, the whole transaction is reversed
|
||||
if (contentTypeIds == null)
|
||||
{
|
||||
var query = Query;
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
{
|
||||
//copy local
|
||||
var id = contentTypeId;
|
||||
var query = Query.Where(x => x.ContentTypeId == id && x.Trashed == false);
|
||||
RebuildXmlStructuresProcessQuery(serializer, query, tr, groupSize);
|
||||
}
|
||||
}
|
||||
|
||||
tr.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildXmlStructuresProcessQuery(Func<IMember, XElement> serializer, IQuery<IMember> query, ITransaction tr, int pageSize)
|
||||
{
|
||||
var pageIndex = 0;
|
||||
long total;
|
||||
var processed = 0;
|
||||
do
|
||||
{
|
||||
var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending, true);
|
||||
|
||||
var xmlItems = (from descendant in descendants
|
||||
let xml = serializer(descendant)
|
||||
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
|
||||
|
||||
//bulk insert it into the database
|
||||
Database.BulkInsertRecords(SqlSyntax, xmlItems, tr);
|
||||
|
||||
processed += xmlItems.Length;
|
||||
|
||||
pageIndex++;
|
||||
} while (processed < total);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using log4net;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -20,13 +17,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IMemberType"/>
|
||||
/// </summary>
|
||||
internal class MemberTypeRepository : ContentTypeBaseRepository<IMemberType>, IMemberTypeRepository
|
||||
internal class MemberTypeRepository : ContentTypeRepositoryBase<IMemberType>, IMemberTypeRepository
|
||||
{
|
||||
|
||||
public MemberTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMappingResolver mappingResolver)
|
||||
: base(work, cache, logger, mappingResolver)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
private FullDataSetRepositoryCachePolicyFactory<IMemberType, int> _cachePolicyFactory;
|
||||
protected override IRepositoryCachePolicyFactory<IMemberType, int> CachePolicyFactory
|
||||
@@ -47,6 +42,37 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IMemberType PerformGet(Guid id)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMemberType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
protected override IMemberType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
@@ -165,28 +191,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
var list = new List<string>
|
||||
{
|
||||
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsContentTypeAllowedContentType WHERE Id = @Id",
|
||||
"DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @Id",
|
||||
"DELETE FROM cmsContentType2ContentType WHERE parentContentTypeId = @Id",
|
||||
"DELETE FROM cmsContentType2ContentType WHERE childContentTypeId = @Id",
|
||||
"DELETE FROM cmsPropertyType WHERE contentTypeId = @Id",
|
||||
"DELETE FROM cmsPropertyTypeGroup WHERE contenttypeNodeId = @Id",
|
||||
"DELETE FROM cmsMemberType WHERE NodeId = @Id",
|
||||
"DELETE FROM cmsContentType WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
};
|
||||
return list;
|
||||
var l = (List<string>)base.GetDeleteClauses(); // we know it's a list
|
||||
l.Add("DELETE FROM cmsMemberType WHERE NodeId = @Id");
|
||||
l.Add("DELETE FROM cmsContentType WHERE nodeId = @Id");
|
||||
l.Add("DELETE FROM umbracoNode WHERE id = @Id");
|
||||
return l;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.MemberType); }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => Constants.ObjectTypes.MemberTypeGuid;
|
||||
|
||||
protected override void PersistNewItem(IMemberType entity)
|
||||
{
|
||||
@@ -278,37 +290,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
propertyTypeAlias);
|
||||
}
|
||||
|
||||
protected override IMemberType PerformGet(Guid id)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMemberType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
protected override IMemberType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that all the built-in membership provider properties have their correct data type
|
||||
/// and property editors assigned. This occurs prior to saving so that the correct values are persisted.
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
internal class ServerRegistrationRepository : NPocoRepositoryBase<int, IServerRegistration>, IServerRegistrationRepository
|
||||
{
|
||||
private readonly ICacheProvider _staticCache;
|
||||
private readonly int[] _lockIds = { Constants.System.ServersLock };
|
||||
|
||||
public ServerRegistrationRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IMappingResolver mappingResolver)
|
||||
: base(work, CacheHelper.CreateDisabledCacheHelper(), logger, mappingResolver)
|
||||
@@ -147,15 +146,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Update<ServerRegistrationDto>("SET isActive=0, isMaster=0 WHERE lastNotifiedDate < @timeoutDate", new { /*timeoutDate =*/ timeoutDate });
|
||||
ReloadCache();
|
||||
}
|
||||
|
||||
public void ReadLockServers()
|
||||
{
|
||||
UnitOfWork.ReadLockNodes(_lockIds);
|
||||
}
|
||||
|
||||
public void WriteLockServers()
|
||||
{
|
||||
UnitOfWork.WriteLockNodes(_lockIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="tagRepo"></param>
|
||||
protected void UpdatePropertyTags(IContentBase entity, ITagRepository tagRepo)
|
||||
protected void UpdateEntityTags(IContentBase entity, ITagRepository tagRepo)
|
||||
{
|
||||
foreach (var tagProp in entity.Properties.Where(x => x.TagSupport.Enable))
|
||||
{
|
||||
@@ -254,6 +254,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasTagProperty(IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.TagSupport.Enable);
|
||||
}
|
||||
|
||||
private Sql<SqlContext> PrepareSqlForPagedResults(Sql<SqlContext> sql, Sql<SqlContext> filterSql, string orderBy, Direction orderDirection, bool orderBySystemField)
|
||||
{
|
||||
@@ -315,14 +319,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
END AS CustomPropVal,
|
||||
cd.nodeId AS CustomPropValContentId
|
||||
FROM cmsDocument cd
|
||||
INNER JOIN cmsPropertyData cpd ON cpd.contentNodeId = cd.nodeId AND cpd.versionId = cd.versionId
|
||||
INNER JOIN cmsPropertyData cpd ON cpd.contentNodeId = cd.nodeId AND cpd.versionId = cd.versionId
|
||||
INNER JOIN cmsPropertyType cpt ON cpt.Id = cpd.propertytypeId
|
||||
WHERE cpt.Alias = @2 AND cd.newest = 1) AS CustomPropData
|
||||
ON CustomPropData.CustomPropValContentId = umbracoNode.id
|
||||
", sortedInt, sortedDecimal, sortedDate, sortedString);
|
||||
|
||||
//insert this just above the LEFT OUTER JOIN
|
||||
var newSql = psql.SQL.Insert(psql.SQL.IndexOf("LEFT OUTER JOIN"), innerJoinTempTable);
|
||||
var newSql = psql.SQL.Insert(psql.SQL.IndexOf("LEFT OUTER JOIN"), innerJoinTempTable);
|
||||
var newArgs = psql.Arguments.ToList();
|
||||
newArgs.Add(orderBy);
|
||||
|
||||
@@ -522,7 +526,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="files"></param>
|
||||
/// <returns></returns>
|
||||
public virtual bool DeleteMediaFiles(IEnumerable<string> files)
|
||||
public virtual bool DeleteMediaFiles(IEnumerable<string> files) // fixme kill eventually
|
||||
{
|
||||
//ensure duplicates are removed
|
||||
files = files.Distinct();
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
string GetWildcardPlaceholder();
|
||||
string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType);
|
||||
string GetStringColumnWildcardComparison(string column, int paramIndex, TextColumnType columnType);
|
||||
string GetConcat(params string[] args);
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for MySql
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute(Constants.DbProviderNames.MySql)]
|
||||
[SqlSyntaxProvider(Constants.DbProviderNames.MySql)]
|
||||
public class MySqlSyntaxProvider : SqlSyntaxProviderBase<MySqlSyntaxProvider>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
@@ -11,14 +11,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Ce
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute(Constants.DbProviderNames.SqlCe)]
|
||||
[SqlSyntaxProvider(Constants.DbProviderNames.SqlCe)]
|
||||
public class SqlCeSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlCeSyntaxProvider>
|
||||
{
|
||||
public SqlCeSyntaxProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override bool SupportsClustered()
|
||||
{
|
||||
return false;
|
||||
@@ -64,7 +59,10 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string GetConcat(params string[] args)
|
||||
{
|
||||
return "(" + string.Join("+", args) + ")";
|
||||
}
|
||||
|
||||
public override string FormatColumnRename(string tableName, string oldName, string newName)
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
public string DateTimeColumnDefinition = "DATETIME";
|
||||
public string TimeColumnDefinition = "DATETIME";
|
||||
|
||||
protected IList<Func<ColumnDefinition, string>> ClauseOrder { get; set; }
|
||||
protected IList<Func<ColumnDefinition, string>> ClauseOrder { get; }
|
||||
|
||||
protected DbTypes DbTypeMap = new DbTypes();
|
||||
protected void InitColumnTypeMap()
|
||||
@@ -172,6 +172,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return string.Format("upper({0}) LIKE '{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetConcat(params string[] args)
|
||||
{
|
||||
return "concat(" + string.Join(",", args) + ")";
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
{
|
||||
UmbracoDatabase Database { get; }
|
||||
|
||||
void ReadLockNodes(params int[] lockIds);
|
||||
void WriteLockNodes(params int[] lockIds);
|
||||
void ReadLock(params int[] lockIds);
|
||||
void WriteLock(params int[] lockIds);
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
/// If any operation is added to the unit of work after it has been completed, then its completion
|
||||
/// status is resetted. So in a way it could be possible to always complete and never flush, but flush
|
||||
/// is preferred when appropriate to indicate that you understand what you are doing.
|
||||
/// Every units of work should be completed, unless a rollback is required. That is, even if the unit of
|
||||
/// work contains only read operations, that do not need to be "commited", the unit of work should be
|
||||
/// properly completed, else it may force an unexpected rollback of a higher-level transaction.
|
||||
/// </remarks>
|
||||
void Complete();
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
_transaction = null;
|
||||
}
|
||||
|
||||
public void ReadLockNodes(params int[] lockIds)
|
||||
public void ReadLock(params int[] lockIds)
|
||||
{
|
||||
Begin(); // we need a transaction
|
||||
|
||||
@@ -78,11 +78,15 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
Database.ExecuteScalar<int>("SELECT sortOrder FROM umbracoNode WHERE id=@id",
|
||||
{
|
||||
var i = Database.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id",
|
||||
new { @id = lockId });
|
||||
if (i == null) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteLockNodes(params int[] lockIds)
|
||||
public void WriteLock(params int[] lockIds)
|
||||
{
|
||||
Begin(); // we need a transaction
|
||||
|
||||
@@ -90,8 +94,12 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
Database.Execute("UPDATE umbracoNode SET sortOrder = (CASE WHEN (sortOrder=1) THEN -1 ELSE 1 END) WHERE id=@id",
|
||||
{
|
||||
var i = Database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id",
|
||||
new { @id = lockId });
|
||||
if (i == 0) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,30 +6,36 @@ using Umbraco.Core.Services;
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of publishing a content item
|
||||
/// Represents the result of publishing a content item.
|
||||
/// </summary>
|
||||
public class PublishStatus : OperationStatus<IContent, PublishStatusType>
|
||||
public class PublishStatus : OperationStatus<PublishStatusType, IContent>
|
||||
{
|
||||
public PublishStatus(IContent content, PublishStatusType statusType, EventMessages eventMessages)
|
||||
: base(content, statusType, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful publish status
|
||||
/// Creates a new instance of the <see cref="PublishStatus"/> class with a status type, event messages, and a content item.
|
||||
/// </summary>
|
||||
public PublishStatus(IContent content, EventMessages eventMessages)
|
||||
: this(content, PublishStatusType.Success, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
public IContent ContentItem
|
||||
{
|
||||
get { return Entity; }
|
||||
}
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
/// <param name="content">The content item.</param>
|
||||
public PublishStatus(PublishStatusType statusType, EventMessages eventMessages, IContent content)
|
||||
: base(statusType, eventMessages, content)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Gets sets the invalid properties if the status failed due to validation.
|
||||
/// Creates a new successful instance of the <see cref="PublishStatus"/> class with a event messages, and a content item.
|
||||
/// </summary>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
/// <param name="content">The content item.</param>
|
||||
public PublishStatus(IContent content, EventMessages eventMessages)
|
||||
: base(PublishStatusType.Success, eventMessages, content)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content item.
|
||||
/// </summary>
|
||||
public IContent ContentItem => Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the invalid properties, if the status failed due to validation.
|
||||
/// </summary>
|
||||
public IEnumerable<Property> InvalidProperties { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// A status type of the result of publishing a content item
|
||||
/// A value indicating the result of publishing a content item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Anything less than 10 = Success!
|
||||
/// <remarks>Do NOT compare against a hard-coded numeric value to check for success or failure,
|
||||
/// but instead use the IsSuccess() extension method defined below - which should be the unique
|
||||
/// place where the numeric test should take place.
|
||||
/// </remarks>
|
||||
public enum PublishStatusType
|
||||
{
|
||||
@@ -14,40 +15,70 @@ namespace Umbraco.Core.Publishing
|
||||
Success = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The item was already published
|
||||
/// The item was already published.
|
||||
/// </summary>
|
||||
SuccessAlreadyPublished = 1,
|
||||
|
||||
// Values below this value indicate a success, values above it indicate a failure.
|
||||
// This value is considered a failure.
|
||||
//Reserved = 10,
|
||||
|
||||
/// <summary>
|
||||
/// The content could not be published because it's ancestor path isn't published
|
||||
/// The content could not be published because it's ancestor path isn't published.
|
||||
/// </summary>
|
||||
FailedPathNotPublished = 10,
|
||||
FailedPathNotPublished = 11,
|
||||
|
||||
/// <summary>
|
||||
/// The content item was scheduled to be un-published and it has expired so we cannot force it to be
|
||||
/// published again as part of a bulk publish operation.
|
||||
/// </summary>
|
||||
FailedHasExpired = 11,
|
||||
FailedHasExpired = 12,
|
||||
|
||||
/// <summary>
|
||||
/// The content item is scheduled to be released in the future and therefore we cannot force it to
|
||||
/// be published during a bulk publish operation.
|
||||
/// </summary>
|
||||
FailedAwaitingRelease = 12,
|
||||
FailedAwaitingRelease = 13,
|
||||
|
||||
/// <summary>
|
||||
/// The content item is in the trash, it cannot be published
|
||||
/// The content item could not be published because it is in the trash.
|
||||
/// </summary>
|
||||
FailedIsTrashed = 13,
|
||||
FailedIsTrashed = 14,
|
||||
|
||||
/// <summary>
|
||||
/// The publish action has been cancelled by an event handler
|
||||
/// The publish action has been cancelled by an event handler.
|
||||
/// </summary>
|
||||
FailedCancelledByEvent = 14,
|
||||
FailedCancelledByEvent = 15,
|
||||
|
||||
/// <summary>
|
||||
/// The content item contains invalid data (has not passed validation requirements)
|
||||
/// The content item could not be published because it contains invalid data (has not passed validation requirements).
|
||||
/// </summary>
|
||||
FailedContentInvalid = 15
|
||||
FailedContentInvalid = 16
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="PublishStatusType"/> enum.
|
||||
/// </summary>
|
||||
public static class PublicStatusTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the status indicates a success.
|
||||
/// </summary>
|
||||
/// <param name="status">The status.</param>
|
||||
/// <returns>A value indicating whether the status indicates a success.</returns>
|
||||
public static bool IsSuccess(this PublishStatusType status)
|
||||
{
|
||||
return (int) status < 10;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the status indicates a failure.
|
||||
/// </summary>
|
||||
/// <param name="status">The status.</param>
|
||||
/// <returns>A value indicating whether the status indicates a failure.</returns>
|
||||
public static bool IsFailure(this PublishStatusType status)
|
||||
{
|
||||
return (int) status >= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,469 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
//TODO: Do we need this anymore??
|
||||
/// <summary>
|
||||
/// Currently acts as an interconnection between the new public api and the legacy api for publishing
|
||||
/// </summary>
|
||||
public class PublishingStrategy : BasePublishingStrategy
|
||||
{
|
||||
private readonly IEventMessagesFactory _eventMessagesFactory;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public PublishingStrategy(IEventMessagesFactory eventMessagesFactory, ILogger logger)
|
||||
{
|
||||
if (eventMessagesFactory == null) throw new ArgumentNullException("eventMessagesFactory");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_eventMessagesFactory = eventMessagesFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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 operation</param>
|
||||
internal Attempt<PublishStatus> PublishInternal(IContent content, int userId)
|
||||
{
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
|
||||
if (Publishing.IsRaisedEventCancelled(
|
||||
new PublishEventArgs<IContent>(content, evtMsgs), this))
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
//Check if the Content is Expired to verify that it can in fact be published
|
||||
if (content.Status == ContentStatus.Expired)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired, evtMsgs));
|
||||
}
|
||||
|
||||
//Check if the Content is Awaiting Release to verify that it can in fact be published
|
||||
if (content.Status == ContentStatus.AwaitingRelease)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease, evtMsgs));
|
||||
}
|
||||
|
||||
//Check if the Content is Trashed to verify that it can in fact be published
|
||||
if (content.Status == ContentStatus.Trashed)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed, evtMsgs));
|
||||
}
|
||||
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
content.Name, content.Id));
|
||||
|
||||
return Attempt.Succeed(new PublishStatus(content, evtMsgs));
|
||||
}
|
||||
|
||||
/// <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 operation</param>
|
||||
/// <returns>True if the publish operation was successfull and not cancelled, otherwise false</returns>
|
||||
public override bool Publish(IContent content, int userId)
|
||||
{
|
||||
return PublishInternal(content, userId).Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a list of content items
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="includeUnpublishedDocuments">
|
||||
/// By default this is set to true which means that it will publish any content item in the list that is completely unpublished and
|
||||
/// not visible on the front-end. If set to false, this will only publish content that is live on the front-end but has new versions
|
||||
/// that have yet to be published.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
///
|
||||
/// This method becomes complex once we start to be able to cancel events or stop publishing a content item in any way because if a
|
||||
/// content item is not published then it's children shouldn't be published either. This rule will apply for the following conditions:
|
||||
/// * If a document fails to be published, do not proceed to publish it's children if:
|
||||
/// ** The document does not have a publish version
|
||||
/// ** The document does have a published version but the includeUnpublishedDocuments = false
|
||||
///
|
||||
/// In order to do this, we will order the content by level and begin by publishing each item at that level, then proceed to the next
|
||||
/// level and so on. If we detect that the above rule applies when the document publishing is cancelled we'll add it to the list of
|
||||
/// parentsIdsCancelled so that it's children don't get published.
|
||||
///
|
||||
/// Its important to note that all 'root' documents included in the list *will* be published regardless of the rules mentioned
|
||||
/// above (unless it is invalid)!! By 'root' documents we are referring to documents in the list with the minimum value for their 'level'.
|
||||
/// In most cases the 'root' documents will only be one document since under normal circumstance we only publish one document and
|
||||
/// its children. The reason we have to do this is because if a user is publishing a document and it's children, it is implied that
|
||||
/// the user definitely wants to publish it even if it has never been published before.
|
||||
///
|
||||
/// </remarks>
|
||||
internal IEnumerable<Attempt<PublishStatus>> PublishWithChildrenInternal(
|
||||
IEnumerable<IContent> content, int userId, bool includeUnpublishedDocuments = true)
|
||||
{
|
||||
var statuses = new List<Attempt<PublishStatus>>();
|
||||
|
||||
//a list of all document ids that had their publishing cancelled during these iterations.
|
||||
//this helps us apply the rule listed in the notes above by checking if a document's parent id
|
||||
//matches one in this list.
|
||||
var parentsIdsCancelled = new List<int>();
|
||||
|
||||
//group by levels and iterate over the sorted ascending level.
|
||||
//TODO: This will cause all queries to execute, they will not be lazy but I'm not really sure being lazy actually made
|
||||
// much difference because we iterate over them all anyways?? Morten?
|
||||
// Because we're grouping I think this will execute all the queries anyways so need to fetch it all first.
|
||||
var fetchedContent = content.ToArray();
|
||||
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
|
||||
//We're going to populate the statuses with all content that is already published because below we are only going to iterate over
|
||||
// content that is not published. We'll set the status to "AlreadyPublished"
|
||||
statuses.AddRange(fetchedContent.Where(x => x.Published)
|
||||
.Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished, evtMsgs))));
|
||||
|
||||
int? firstLevel = null;
|
||||
|
||||
//group by level and iterate over each level (sorted ascending)
|
||||
var levelGroups = fetchedContent.GroupBy(x => x.Level);
|
||||
foreach (var level in levelGroups.OrderBy(x => x.Key))
|
||||
{
|
||||
//set the first level flag, used to ensure that all documents at the first level will
|
||||
//be published regardless of the rules mentioned in the remarks.
|
||||
if (!firstLevel.HasValue)
|
||||
{
|
||||
firstLevel = level.Key;
|
||||
}
|
||||
|
||||
/* Only update content thats not already been published - we want to loop through
|
||||
* all unpublished content to write skipped content (expired and awaiting release) to log.
|
||||
*/
|
||||
foreach (var item in level.Where(x => x.Published == false))
|
||||
{
|
||||
//Check if this item should be excluded because it's parent's publishing has failed/cancelled
|
||||
if (parentsIdsCancelled.Contains(item.ParentId))
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because it's parent's publishing action failed or was cancelled.", item.Name, item.Id));
|
||||
//if this cannot be published, ensure that it's children can definitely not either!
|
||||
parentsIdsCancelled.Add(item.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if this item has never been published (and that it is not at the root level)
|
||||
if (item.Level != firstLevel && !includeUnpublishedDocuments && !item.HasPublishedVersion())
|
||||
{
|
||||
//this item does not have a published version and the flag is set to not include them
|
||||
parentsIdsCancelled.Add(item.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Fire Publishing event
|
||||
if (Publishing.IsRaisedEventCancelled(
|
||||
new PublishEventArgs<IContent>(item, evtMsgs), this))
|
||||
{
|
||||
//the publishing has been cancelled.
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if the content is valid if the flag is set to check
|
||||
if (item.IsValid() == false)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if the Content is Expired to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.Expired)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if the Content is Awaiting Release to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.AwaitingRelease)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if the Content is Trashed to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.Trashed)
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
item.ChangePublishedState(PublishedState.Published);
|
||||
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
item.Name, item.Id));
|
||||
|
||||
statuses.Add(Attempt.Succeed(new PublishStatus(item, evtMsgs)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return statuses;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Based on the information provider we'll check if we should cancel the publishing of this document's children
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="parentsIdsCancelled"></param>
|
||||
/// <param name="includeUnpublishedDocuments"></param>
|
||||
/// <remarks>
|
||||
/// See remarks on method: PublishWithChildrenInternal
|
||||
/// </remarks>
|
||||
private void CheckCancellingOfChildPublishing(IContent content, List<int> parentsIdsCancelled, bool includeUnpublishedDocuments)
|
||||
{
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
//TODO: We're going back to the service layer here... not sure how to avoid this? And this will add extra overhead to
|
||||
// any document that fails to publish...
|
||||
var hasPublishedVersion = ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
|
||||
if (hasPublishedVersion && !includeUnpublishedDocuments)
|
||||
{
|
||||
//it has a published version but our flag tells us to not include un-published documents and therefore we should
|
||||
// not be forcing decendant/child documents to be published if their parent fails.
|
||||
parentsIdsCancelled.Add(content.Id);
|
||||
}
|
||||
else if (!hasPublishedVersion)
|
||||
{
|
||||
//it doesn't have a published version so we certainly cannot publish it's children.
|
||||
parentsIdsCancelled.Add(content.Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a list of Content
|
||||
/// </summary>
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/></param>
|
||||
/// <param name="userId">Id of the User issueing the publish operation</param>
|
||||
/// <returns>True if the publish operation was successfull and not cancelled, otherwise false</returns>
|
||||
public override bool PublishWithChildren(IEnumerable<IContent> content, int userId)
|
||||
{
|
||||
var result = PublishWithChildrenInternal(content, userId);
|
||||
|
||||
//NOTE: This previously always returned true so I've left it that way. It returned true because (from Morten)...
|
||||
// ... if one item couldn't be published it wouldn't be correct to return false.
|
||||
// in retrospect it should have returned a list of with Ids and Publish Status
|
||||
// come to think of it ... the cache would still be updated for a failed item or at least tried updated.
|
||||
// It would call the Published event for the entire list, but if the Published property isn't set to True it
|
||||
// wouldn't actually update the cache for that item. But not really ideal nevertheless...
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <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 operation</param>
|
||||
/// <returns>True if the unpublish operation was successfull and not cancelled, otherwise false</returns>
|
||||
public override bool UnPublish(IContent content, int userId)
|
||||
{
|
||||
return UnPublishInternal(content, userId).Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpublishes a list of Content
|
||||
/// </summary>
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/></param>
|
||||
/// <param name="userId">Id of the User issueing the unpublish operation</param>
|
||||
/// <returns>A list of publish statuses</returns>
|
||||
private IEnumerable<Attempt<PublishStatus>> UnPublishInternal(IEnumerable<IContent> content, int userId)
|
||||
{
|
||||
return content.Select(x => UnPublishInternal(x, userId));
|
||||
}
|
||||
|
||||
private Attempt<PublishStatus> UnPublishInternal(IContent content, int userId)
|
||||
{
|
||||
// content should (is assumed to ) be the newest version, which may not be published
|
||||
// don't know how to test this, so it's not verified
|
||||
// NOTE
|
||||
// if published != newest, then the published flags need to be reseted by whoever is calling that method
|
||||
// at the moment it's done by the content service
|
||||
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
|
||||
//Fire UnPublishing event
|
||||
if (UnPublishing.IsRaisedEventCancelled(
|
||||
new PublishEventArgs<IContent>(content, evtMsgs), this))
|
||||
{
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be unpublished, the event was cancelled.", content.Name, content.Id));
|
||||
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
//If Content has a release date set to before now, it should be removed so it doesn't interrupt an unpublish
|
||||
//Otherwise it would remain released == published
|
||||
if (content.ReleaseDate.HasValue && content.ReleaseDate.Value <= DateTime.Now)
|
||||
{
|
||||
content.ReleaseDate = null;
|
||||
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' had its release date removed, because it was unpublished.",
|
||||
content.Name, content.Id));
|
||||
}
|
||||
|
||||
// if newest is published, unpublish
|
||||
if (content.Published)
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
|
||||
content.Name, content.Id));
|
||||
|
||||
return Attempt.Succeed(new PublishStatus(content, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpublishes a list of Content
|
||||
/// </summary>
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/></param>
|
||||
/// <param name="userId">Id of the User issueing the unpublish operation</param>
|
||||
/// <returns>True if the unpublish operation was successfull and not cancelled, otherwise false</returns>
|
||||
public override bool UnPublish(IEnumerable<IContent> content, int userId)
|
||||
{
|
||||
var result = UnPublishInternal(content, userId);
|
||||
|
||||
//NOTE: This previously always returned true so I've left it that way. It returned true because (from Morten)...
|
||||
// ... if one item couldn't be published it wouldn't be correct to return false.
|
||||
// in retrospect it should have returned a list of with Ids and Publish Status
|
||||
// come to think of it ... the cache would still be updated for a failed item or at least tried updated.
|
||||
// It would call the Published event for the entire list, but if the Published property isn't set to True it
|
||||
// wouldn't actually update the cache for that item. But not really ideal nevertheless...
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to fire event that updating the published content has finalized.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This seperation of the OnPublished event is done to ensure that the Content
|
||||
/// has been properly updated (committed unit of work) and xml saved in the db.
|
||||
/// </remarks>
|
||||
/// <param name="content"><see cref="IContent"/> thats being published</param>
|
||||
public override void PublishingFinalized(IContent content)
|
||||
{
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
Published.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to fire event that updating the published content has finalized.
|
||||
/// </summary>
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/> thats being published</param>
|
||||
/// <param name="isAllRepublished">Boolean indicating whether its all content that is republished</param>
|
||||
public override void PublishingFinalized(IEnumerable<IContent> content, bool isAllRepublished)
|
||||
{
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
Published.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, isAllRepublished, evtMsgs), this);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to fire event that updating the unpublished content has finalized.
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> thats being unpublished</param>
|
||||
public override void UnPublishingFinalized(IContent content)
|
||||
{
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
UnPublished.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to fire event that updating the unpublished content has finalized.
|
||||
/// </summary>
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/> thats being unpublished</param>
|
||||
public override void UnPublishingFinalized(IEnumerable<IContent> content)
|
||||
{
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
UnPublished.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before publish
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublishingStrategy, PublishEventArgs<IContent>> Publishing;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after publish
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublishingStrategy, PublishEventArgs<IContent>> Published;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before unpublish
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublishingStrategy, PublishEventArgs<IContent>> UnPublishing;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after unpublish
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublishingStrategy, PublishEventArgs<IContent>> UnPublished;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,32 @@ using Umbraco.Core.Services;
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of unpublishing a content item
|
||||
/// Represents the result of unpublishing a content item.
|
||||
/// </summary>
|
||||
public class UnPublishStatus : OperationStatus<IContent, UnPublishedStatusType>
|
||||
public class UnPublishStatus : OperationStatus<UnPublishedStatusType, IContent>
|
||||
{
|
||||
public UnPublishStatus(IContent content, UnPublishedStatusType statusType, EventMessages eventMessages)
|
||||
: base(content, statusType, eventMessages)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="UnPublishStatus"/> class with a status type, event messages, and a content item.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
/// <param name="content">The content item.</param>
|
||||
public UnPublishStatus(UnPublishedStatusType statusType, EventMessages eventMessages, IContent content)
|
||||
: base(statusType, eventMessages, content)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful unpublish status
|
||||
/// Creates a new successful instance of the <see cref="UnPublishStatus"/> class with a event messages, and a content item.
|
||||
/// </summary>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
/// <param name="content">The content item.</param>
|
||||
public UnPublishStatus(IContent content, EventMessages eventMessages)
|
||||
: this(content, UnPublishedStatusType.Success, eventMessages)
|
||||
{
|
||||
}
|
||||
: base(UnPublishedStatusType.Success, eventMessages, content)
|
||||
{ }
|
||||
|
||||
public IContent ContentItem
|
||||
{
|
||||
get { return Entity; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the content item.
|
||||
/// </summary>
|
||||
public IContent ContentItem => Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static class ServiceContextExtensions
|
||||
{
|
||||
public static IContentTypeServiceBase<T> GetContentTypeService<T>(this ServiceContext services)
|
||||
where T : IContentTypeComposition
|
||||
{
|
||||
if (typeof(T).Implements<IContentType>())
|
||||
return services.ContentTypeService as IContentTypeServiceBase<T>;
|
||||
if (typeof(T).Implements<IMediaType>())
|
||||
return services.MediaTypeService as IContentTypeServiceBase<T>;
|
||||
if (typeof(T).Implements<IMemberType>())
|
||||
return services.MemberTypeService as IContentTypeServiceBase<T>;
|
||||
throw new ArgumentException("Type " + typeof(T).FullName + " does not have a service.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repo = uow.CreateRepository<IAuditRepository>();
|
||||
var result = repo.GetByQuery(repo.Query.Where(x => x.Id == objectId));
|
||||
uow.Complete();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -45,6 +46,7 @@ namespace Umbraco.Core.Services
|
||||
var result = sinceDate.HasValue == false
|
||||
? repo.GetByQuery(repo.Query.Where(x => x.UserId == userId && x.AuditType == type))
|
||||
: repo.GetByQuery(repo.Query.Where(x => x.UserId == userId && x.AuditType == type && x.CreateDate >= sinceDate.Value));
|
||||
uow.Complete();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -57,6 +59,7 @@ namespace Umbraco.Core.Services
|
||||
var result = sinceDate.HasValue == false
|
||||
? repo.GetByQuery(repo.Query.Where(x => x.AuditType == type))
|
||||
: repo.GetByQuery(repo.Query.Where(x => x.AuditType == type && x.CreateDate >= sinceDate.Value));
|
||||
uow.Complete();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -67,6 +70,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repo = uow.CreateRepository<IAuditRepository>();
|
||||
repo.CleanLogs(maximumAgeOfLogsInMinutes);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1452
-1241
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public class ContentTypeServiceBase : RepositoryService
|
||||
internal abstract class ContentTypeServiceBase : RepositoryService
|
||||
{
|
||||
public ContentTypeServiceBase(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory)
|
||||
protected ContentTypeServiceBase(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
}
|
||||
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// This is called after an content type is saved and is used to update the content xml structures in the database
|
||||
/// if they are required to be updated.
|
||||
@@ -33,7 +35,7 @@ namespace Umbraco.Core.Services
|
||||
// - a content type changes it's alias OR
|
||||
// - if a content type has it's property removed OR
|
||||
// - if a content type has a property whose alias has changed
|
||||
//here we need to check if the alias of the content type changed or if one of the properties was removed.
|
||||
//here we need to check if the alias of the content type changed or if one of the properties was removed.
|
||||
var dirty = contentType as IRememberBeingDirty;
|
||||
if (dirty == null) continue;
|
||||
|
||||
@@ -50,18 +52,18 @@ namespace Umbraco.Core.Services
|
||||
&& (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias))
|
||||
{
|
||||
//If the alias was changed then we only need to update the xml structures for content of the current content type.
|
||||
//If a property was deleted or a property alias was changed then we need to update the xml structures for any
|
||||
//If a property was deleted or a property alias was changed then we need to update the xml structures for any
|
||||
// content of the current content type and any of the content type's child content types.
|
||||
if (dirty.WasPropertyDirty("Alias")
|
||||
&& dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false)
|
||||
{
|
||||
//if only the alias changed then only update the current content type
|
||||
//if only the alias changed then only update the current content type
|
||||
toUpdate.Add(contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if a property was deleted or alias changed, then update all content of the current content type
|
||||
// and all of it's desscendant doc types.
|
||||
// and all of it's desscendant doc types.
|
||||
toUpdate.AddRange(contentType.DescendantsAndSelf());
|
||||
}
|
||||
}
|
||||
@@ -71,4 +73,887 @@ namespace Umbraco.Core.Services
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class ContentTypeServiceBase<TItem, TService> : ContentTypeServiceBase
|
||||
where TItem : class, IContentTypeComposition
|
||||
where TService : class, IContentTypeServiceBase<TItem>
|
||||
{
|
||||
protected ContentTypeServiceBase(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_this = this as TService;
|
||||
if (_this == null) throw new Exception("Oops.");
|
||||
}
|
||||
|
||||
private readonly TService _this;
|
||||
|
||||
public static event TypedEventHandler<TService, SaveEventArgs<TItem>> Saving;
|
||||
public static event TypedEventHandler<TService, SaveEventArgs<TItem>> Saved;
|
||||
|
||||
protected void OnSaving(SaveEventArgs<TItem> args)
|
||||
{
|
||||
Saving.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
protected bool OnSavingCancelled(SaveEventArgs<TItem> args)
|
||||
{
|
||||
return Saving.IsRaisedEventCancelled(args, _this);
|
||||
}
|
||||
|
||||
protected void OnSaved(SaveEventArgs<TItem> args)
|
||||
{
|
||||
Saved.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
public static event TypedEventHandler<TService, DeleteEventArgs<TItem>> Deleting;
|
||||
public static event TypedEventHandler<TService, DeleteEventArgs<TItem>> Deleted;
|
||||
|
||||
protected void OnDeleting(DeleteEventArgs<TItem> args)
|
||||
{
|
||||
Deleting.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
protected bool OnDeletingCancelled(DeleteEventArgs<TItem> args)
|
||||
{
|
||||
return Deleting.IsRaisedEventCancelled(args, _this);
|
||||
}
|
||||
|
||||
protected void OnDeleted(DeleteEventArgs<TItem> args)
|
||||
{
|
||||
Deleted.RaiseEvent(args, (TService)(object)this);
|
||||
}
|
||||
|
||||
public static event TypedEventHandler<TService, MoveEventArgs<TItem>> Moving;
|
||||
public static event TypedEventHandler<TService, MoveEventArgs<TItem>> Moved;
|
||||
|
||||
protected void OnMoving(MoveEventArgs<TItem> args)
|
||||
{
|
||||
Moving.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
protected bool OnMovingCancelled(MoveEventArgs<TItem> args)
|
||||
{
|
||||
return Moving.IsRaisedEventCancelled(args, _this);
|
||||
}
|
||||
|
||||
protected void OnMoved(MoveEventArgs<TItem> args)
|
||||
{
|
||||
Moved.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
public static event TypedEventHandler<TService, SaveEventArgs<EntityContainer>> SavingContainer;
|
||||
public static event TypedEventHandler<TService, SaveEventArgs<EntityContainer>> SavedContainer;
|
||||
|
||||
protected void OnSavingContainer(SaveEventArgs<EntityContainer> args)
|
||||
{
|
||||
SavingContainer.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
protected bool OnSavingContainerCancelled(SaveEventArgs<EntityContainer> args)
|
||||
{
|
||||
return SavingContainer.IsRaisedEventCancelled(args, _this);
|
||||
}
|
||||
|
||||
protected void OnSavedContainer(SaveEventArgs<EntityContainer> args)
|
||||
{
|
||||
SavedContainer.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
public static event TypedEventHandler<TService, DeleteEventArgs<EntityContainer>> DeletingContainer;
|
||||
public static event TypedEventHandler<TService, DeleteEventArgs<EntityContainer>> DeletedContainer;
|
||||
|
||||
protected void OnDeletingContainer(DeleteEventArgs<EntityContainer> args)
|
||||
{
|
||||
DeletingContainer.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
protected bool OnDeletingContainerCancelled(DeleteEventArgs<EntityContainer> args)
|
||||
{
|
||||
return DeletingContainer.IsRaisedEventCancelled(args, _this);
|
||||
}
|
||||
|
||||
protected void OnDeletedContainer(DeleteEventArgs<EntityContainer> args)
|
||||
{
|
||||
DeletedContainer.RaiseEvent(args, _this);
|
||||
}
|
||||
|
||||
// for later usage
|
||||
//public static event TypedEventHandler<TService, Change.EventArgs> TxRefreshed;
|
||||
|
||||
//protected void OnTxRefreshed(Change.EventArgs args)
|
||||
//{
|
||||
// TxRefreshed.RaiseEvent(args, this);
|
||||
//}
|
||||
}
|
||||
|
||||
internal abstract class ContentTypeServiceBase<TRepository, TItem, TService> : ContentTypeServiceBase<TItem, TService>, IContentTypeServiceBase<TItem>
|
||||
where TRepository : IContentTypeRepositoryBase<TItem>
|
||||
where TItem : class, IContentTypeComposition
|
||||
where TService : class, IContentTypeServiceBase<TItem>
|
||||
{
|
||||
protected ContentTypeServiceBase(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{ }
|
||||
|
||||
protected abstract int[] WriteLockIds { get; }
|
||||
protected abstract int[] ReadLockIds { get; }
|
||||
|
||||
#region Validation
|
||||
|
||||
public Attempt<string[]> ValidateComposition(TItem compo)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
ValidateLocked(repo, compo);
|
||||
uow.Complete();
|
||||
}
|
||||
return Attempt<string[]>.Succeed();
|
||||
}
|
||||
catch (InvalidCompositionException ex)
|
||||
{
|
||||
return Attempt.Fail(ex.PropertyTypeAliases, ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ValidateLocked(TRepository repository, TItem compositionContentType)
|
||||
{
|
||||
// performs business-level validation of the composition
|
||||
// should ensure that it is absolutely safe to save the composition
|
||||
|
||||
// eg maybe a property has been added, with an alias that's OK (no conflict with ancestors)
|
||||
// but that cannot be used (conflict with descendants)
|
||||
|
||||
var allContentTypes = repository.GetAll(new int[0]).Cast<IContentTypeComposition>().ToArray();
|
||||
|
||||
var compositionAliases = compositionContentType.CompositionAliases();
|
||||
var compositions = allContentTypes.Where(x => compositionAliases.Any(y => x.Alias.Equals(y)));
|
||||
var propertyTypeAliases = compositionContentType.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).ToArray();
|
||||
var indirectReferences = allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == compositionContentType.Id));
|
||||
var comparer = new DelegateEqualityComparer<IContentTypeComposition>((x, y) => x.Id == y.Id, x => x.Id);
|
||||
var dependencies = new HashSet<IContentTypeComposition>(compositions, comparer);
|
||||
var stack = new Stack<IContentTypeComposition>();
|
||||
indirectReferences.ForEach(stack.Push); // push indirect references to a stack, so we can add recursively
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var indirectReference = stack.Pop();
|
||||
dependencies.Add(indirectReference);
|
||||
// get all compositions for the current indirect reference
|
||||
var directReferences = indirectReference.ContentTypeComposition;
|
||||
|
||||
foreach (var directReference in directReferences)
|
||||
{
|
||||
if (directReference.Id == compositionContentType.Id || directReference.Alias.Equals(compositionContentType.Alias)) continue;
|
||||
dependencies.Add(directReference);
|
||||
// a direct reference has compositions of its own - these also need to be taken into account
|
||||
var directReferenceGraph = directReference.CompositionAliases();
|
||||
allContentTypes.Where(x => directReferenceGraph.Any(y => x.Alias.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ForEach(c => dependencies.Add(c));
|
||||
}
|
||||
// recursive lookup of indirect references
|
||||
allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == indirectReference.Id)).ForEach(stack.Push);
|
||||
}
|
||||
|
||||
foreach (var dependency in dependencies)
|
||||
{
|
||||
if (dependency.Id == compositionContentType.Id) continue;
|
||||
var contentTypeDependency = allContentTypes.FirstOrDefault(x => x.Alias.Equals(dependency.Alias, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (contentTypeDependency == null) continue;
|
||||
var intersect = contentTypeDependency.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).Intersect(propertyTypeAliases).ToArray();
|
||||
if (intersect.Length == 0) continue;
|
||||
|
||||
throw new InvalidCompositionException(compositionContentType.Alias, intersect.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Composition
|
||||
#endregion
|
||||
|
||||
#region Get, Has, Is, Count
|
||||
|
||||
public TItem Get(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var item = repo.Get(id);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public TItem Get(string alias)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var item = repo.Get(alias);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public TItem Get(Guid id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var item = repo.Get(id);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetAll(params int[] ids)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var items = repo.GetAll(ids);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetAll(params Guid[] ids)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
// IReadRepository<Guid, TEntity> is explicitely implemented, need to cast the repo
|
||||
var items = ((IReadRepository<Guid, TItem>) repo).GetAll(ids);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetChildren(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var query = repo.Query.Where(x => x.ParentId == id);
|
||||
var items = repo.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetChildren(Guid id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var found = Get(id);
|
||||
if (found == null) return Enumerable.Empty<TItem>();
|
||||
var query = repo.Query.Where(x => x.ParentId == found.Id);
|
||||
var items = repo.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasChildren(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var query = repo.Query.Where(x => x.ParentId == id);
|
||||
var count = repo.Count(query);
|
||||
uow.Complete();
|
||||
return count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasChildren(Guid id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var found = Get(id);
|
||||
if (found == null) return false;
|
||||
var query = repo.Query.Where(x => x.ParentId == found.Id);
|
||||
var count = repo.Count(query);
|
||||
uow.Complete();
|
||||
return count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetDescendants(int id, bool andSelf)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
|
||||
var descendants = new List<TItem>();
|
||||
if (andSelf) descendants.Add(repo.Get(id));
|
||||
var ids = new Stack<int>();
|
||||
ids.Push(id);
|
||||
|
||||
while (ids.Count > 0)
|
||||
{
|
||||
var i = ids.Pop();
|
||||
var query = repo.Query.Where(x => x.ParentId == i);
|
||||
var result = repo.GetByQuery(query).ToArray();
|
||||
|
||||
foreach (var c in result)
|
||||
{
|
||||
descendants.Add(c);
|
||||
ids.Push(c.Id);
|
||||
}
|
||||
}
|
||||
|
||||
var descendantsA = descendants.ToArray();
|
||||
uow.Complete();
|
||||
return descendantsA;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetComposedOf(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
|
||||
// hash set handles duplicates
|
||||
var composed = new HashSet<TItem>(new DelegateEqualityComparer<TItem>(
|
||||
(x, y) => x.Id == y.Id,
|
||||
x => x.Id.GetHashCode()));
|
||||
|
||||
var ids = new Stack<int>();
|
||||
ids.Push(id);
|
||||
|
||||
while (ids.Count > 0)
|
||||
{
|
||||
var i = ids.Pop();
|
||||
var result = repo.GetTypesDirectlyComposedOf(i).ToArray();
|
||||
|
||||
foreach (var c in result)
|
||||
{
|
||||
composed.Add(c);
|
||||
ids.Push(c.Id);
|
||||
}
|
||||
}
|
||||
|
||||
var composedA = composed.ToArray();
|
||||
uow.Complete();
|
||||
return composedA;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.ReadLock(ReadLockIds);
|
||||
var count = repo.Count(repo.Query);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
|
||||
public void Save(TItem item, int userId = 0)
|
||||
{
|
||||
if (OnSavingCancelled(new SaveEventArgs<TItem>(item)))
|
||||
return;
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.WriteLock(WriteLockIds);
|
||||
|
||||
// validate the DAG transform, within the lock
|
||||
ValidateLocked(repo, item); // throws if invalid
|
||||
|
||||
item.CreatorId = userId;
|
||||
repo.AddOrUpdate(item); // also updates content/media/member items
|
||||
uow.Flush(); // to db but no commit yet
|
||||
|
||||
// ...
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
// todo: should use TxRefreshed event within the transaction instead, see CC branch
|
||||
UpdateContentXmlStructure(item);
|
||||
|
||||
OnSaved(new SaveEventArgs<TItem>(item, false));
|
||||
Audit(AuditType.Save, $"Save {typeof(TItem).Name} performed by user", userId, item.Id);
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<TItem> items, int userId = 0)
|
||||
{
|
||||
var itemsA = items.ToArray();
|
||||
|
||||
if (OnSavingCancelled(new SaveEventArgs<TItem>(itemsA)))
|
||||
return;
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.WriteLock(WriteLockIds);
|
||||
|
||||
// all-or-nothing, validate them all first
|
||||
foreach (var contentType in itemsA)
|
||||
{
|
||||
ValidateLocked(repo, contentType); // throws if invalid
|
||||
}
|
||||
foreach (var contentType in itemsA)
|
||||
{
|
||||
contentType.CreatorId = userId;
|
||||
repo.AddOrUpdate(contentType);
|
||||
}
|
||||
|
||||
//save it all in one go
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
// todo: should use TxRefreshed event within the transaction instead, see CC branch
|
||||
UpdateContentXmlStructure(itemsA.Cast<IContentTypeBase>().ToArray());
|
||||
|
||||
OnSaved(new SaveEventArgs<TItem>(itemsA, false));
|
||||
Audit(AuditType.Save, $"Save {typeof(TItem).Name} performed by user", userId, -1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete
|
||||
|
||||
public void Delete(TItem item, int userId = 0)
|
||||
{
|
||||
if (OnDeletingCancelled(new DeleteEventArgs<TItem>(item)))
|
||||
return;
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.WriteLock(WriteLockIds);
|
||||
|
||||
// all descendants are going to be deleted
|
||||
var descendantsAndSelf = item.DescendantsAndSelf()
|
||||
.ToArray();
|
||||
|
||||
// delete content
|
||||
DeleteItemsOfTypes(descendantsAndSelf.Select(x => x.Id));
|
||||
|
||||
// finally delete the content type
|
||||
// - recursively deletes all descendants
|
||||
// - deletes all associated property data
|
||||
// (contents of any descendant type have been deleted but
|
||||
// contents of any composed (impacted) type remain but
|
||||
// need to have their property data cleared)
|
||||
repo.Delete(item);
|
||||
uow.Flush(); // to db but no commit yet
|
||||
|
||||
//...
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
OnDeleted(new DeleteEventArgs<TItem>(item, false));
|
||||
Audit(AuditType.Delete, $"Delete {typeof(TItem).Name} performed by user", userId, item.Id);
|
||||
}
|
||||
|
||||
public void Delete(IEnumerable<TItem> items, int userId = 0)
|
||||
{
|
||||
var itemsA = items.ToArray();
|
||||
|
||||
if (OnDeletingCancelled(new DeleteEventArgs<TItem>(itemsA)))
|
||||
return;
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.WriteLock(WriteLockIds);
|
||||
|
||||
// all descendants are going to be deleted
|
||||
var allDescendantsAndSelf = itemsA.SelectMany(xx => xx.DescendantsAndSelf())
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
// delete content
|
||||
DeleteItemsOfTypes(allDescendantsAndSelf.Select(x => x.Id));
|
||||
|
||||
// finally delete the content types
|
||||
// (see notes in overload)
|
||||
foreach (var item in itemsA)
|
||||
repo.Delete(item);
|
||||
|
||||
uow.Flush(); // to db but no commit yet
|
||||
|
||||
// ...
|
||||
|
||||
uow.Complete();
|
||||
|
||||
}
|
||||
|
||||
OnDeleted(new DeleteEventArgs<TItem>(itemsA, false));
|
||||
Audit(AuditType.Delete, $"Delete {typeof(TItem).Name} performed by user", userId, -1);
|
||||
}
|
||||
|
||||
protected abstract void DeleteItemsOfTypes(IEnumerable<int> typeIds);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Copy
|
||||
|
||||
public TItem Copy(TItem original, string alias, string name, int parentId = -1)
|
||||
{
|
||||
TItem parent = null;
|
||||
if (parentId > 0)
|
||||
{
|
||||
parent = Get(parentId);
|
||||
if (parent == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not find parent with id " + parentId);
|
||||
}
|
||||
}
|
||||
return Copy(original, alias, name, parent);
|
||||
}
|
||||
|
||||
public TItem Copy(TItem original, string alias, string name, TItem parent)
|
||||
{
|
||||
Mandate.ParameterNotNull(original, "original");
|
||||
Mandate.ParameterNotNullOrEmpty(alias, "alias");
|
||||
|
||||
if (parent != null)
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent must have an identity"));
|
||||
|
||||
// this is illegal
|
||||
//var originalb = (ContentTypeCompositionBase)original;
|
||||
// but we *know* it has to be a ContentTypeCompositionBase anyways
|
||||
var originalb = (ContentTypeCompositionBase) (object) original;
|
||||
var clone = (TItem) originalb.DeepCloneWithResetIdentities(alias);
|
||||
|
||||
clone.Name = name;
|
||||
|
||||
//remove all composition that is not it's current alias
|
||||
var compositionAliases = clone.CompositionAliases().Except(new[] { alias }).ToList();
|
||||
foreach (var a in compositionAliases)
|
||||
{
|
||||
clone.RemoveContentType(a);
|
||||
}
|
||||
|
||||
//if a parent is specified set it's composition and parent
|
||||
if (parent != null)
|
||||
{
|
||||
//add a new parent composition
|
||||
clone.AddContentType(parent);
|
||||
clone.ParentId = parent.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
//set to root
|
||||
clone.ParentId = -1;
|
||||
}
|
||||
|
||||
Save(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<MoveOperationStatusType, TItem>> Copy(TItem copying, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
TItem copy;
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
uow.WriteLock(WriteLockIds);
|
||||
|
||||
var containerRepository = uow.CreateContainerRepository(ContainerObjectType);
|
||||
try
|
||||
{
|
||||
if (containerId > 0)
|
||||
{
|
||||
var container = containerRepository.Get(containerId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound); // causes rollback
|
||||
}
|
||||
var alias = repo.GetUniqueAlias(copying.Alias);
|
||||
|
||||
// this is illegal
|
||||
//var copyingb = (ContentTypeCompositionBase) copying;
|
||||
// but we *know* it has to be a ContentTypeCompositionBase anyways
|
||||
var copyingb = (ContentTypeCompositionBase) (object)copying;
|
||||
copy = (TItem) copyingb.DeepCloneWithResetIdentities(alias);
|
||||
|
||||
copy.Name = copy.Name + " (copy)"; // might not be unique
|
||||
|
||||
// if it has a parent, and the parent is a content type, unplug composition
|
||||
// all other compositions remain in place in the copied content type
|
||||
if (copy.ParentId > 0)
|
||||
{
|
||||
var parent = repo.Get(copy.ParentId);
|
||||
if (parent != null)
|
||||
copy.RemoveContentType(parent.Alias);
|
||||
}
|
||||
|
||||
copy.ParentId = containerId;
|
||||
repo.AddOrUpdate(copy);
|
||||
uow.Complete();
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return OperationStatus.Attempt.Fail<MoveOperationStatusType, TItem>(ex.Operation, evtMsgs); // causes rollback
|
||||
}
|
||||
}
|
||||
|
||||
return OperationStatus.Attempt.Succeed(MoveOperationStatusType.Success, evtMsgs, copy);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Move
|
||||
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> Move(TItem moving, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (OnMovingCancelled(new MoveEventArgs<TItem>(evtMsgs, new MoveEventInfo<TItem>(moving, moving.Path, containerId))))
|
||||
return OperationStatus.Attempt.Fail(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs);
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<TItem>>();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(WriteLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateRepository<TRepository>();
|
||||
var containerRepo = uow.CreateRepository<IDocumentTypeContainerRepository>();
|
||||
|
||||
try
|
||||
{
|
||||
EntityContainer container = null;
|
||||
if (containerId > 0)
|
||||
{
|
||||
container = containerRepo.Get(containerId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound); // causes rollback
|
||||
}
|
||||
moveInfo.AddRange(repo.Move(moving, container));
|
||||
uow.Complete();
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return OperationStatus.Attempt.Fail(ex.Operation, evtMsgs); // causes rollback
|
||||
}
|
||||
}
|
||||
|
||||
OnMoved(new MoveEventArgs<TItem>(false, evtMsgs, moveInfo.ToArray()));
|
||||
|
||||
return OperationStatus.Attempt.Succeed(MoveOperationStatusType.Success, evtMsgs);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Containers
|
||||
|
||||
protected abstract Guid ContainedObjectType { get; }
|
||||
|
||||
protected Guid ContainerObjectType => EntityContainer.GetContainerObjectType(ContainedObjectType);
|
||||
|
||||
public Attempt<OperationStatus<OperationStatusType, EntityContainer>> CreateContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(WriteLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(ContainerObjectType);
|
||||
try
|
||||
{
|
||||
var container = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid)
|
||||
{
|
||||
Name = name,
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (OnSavingContainerCancelled(new SaveEventArgs<EntityContainer>(container, evtMsgs)))
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs, container); // causes rollback
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Complete();
|
||||
|
||||
OnSavedContainer(new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, container);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return OperationStatus.Attempt.Fail<OperationStatusType, EntityContainer>(OperationStatusType.FailedCancelledByEvent, evtMsgs, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
var containerObjectType = ContainerObjectType;
|
||||
if (container.ContainedObjectType != containerObjectType)
|
||||
{
|
||||
var ex = new InvalidOperationException("Not a container of the proper type.");
|
||||
return OperationStatus.Attempt.Fail(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (container.HasIdentity && container.IsPropertyDirty("ParentId"))
|
||||
{
|
||||
var ex = new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
return OperationStatus.Attempt.Fail(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (OnSavingContainerCancelled(new SaveEventArgs<EntityContainer>(container, evtMsgs)))
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(WriteLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(containerObjectType);
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
OnSavedContainer(new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
public EntityContainer GetContainer(int containerId)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(ReadLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(ContainerObjectType);
|
||||
var container = repo.Get(containerId);
|
||||
uow.Complete();
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public EntityContainer GetContainer(Guid containerId)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(ReadLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(ContainerObjectType);
|
||||
var container = ((EntityContainerRepository) repo).Get(containerId);
|
||||
uow.Complete();
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContainers(int[] containerIds)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(ReadLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(ContainerObjectType);
|
||||
var containers = repo.GetAll(containerIds);
|
||||
uow.Complete();
|
||||
return containers;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContainers(TItem item)
|
||||
{
|
||||
var ancestorIds = item.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x =>
|
||||
{
|
||||
var asInt = x.TryConvertTo<int>();
|
||||
return asInt ? asInt.Result : int.MinValue;
|
||||
})
|
||||
.Where(x => x != int.MinValue && x != item.Id)
|
||||
.ToArray();
|
||||
|
||||
return GetContainers(ancestorIds);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContainers(string name, int level)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(ReadLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(ContainerObjectType);
|
||||
var containers = ((EntityContainerRepository) repo).Get(name, level);
|
||||
uow.Complete();
|
||||
return containers;
|
||||
}
|
||||
}
|
||||
|
||||
// fixme - what happens if deleting a non-empty container?
|
||||
public Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(WriteLockIds); // also for containers
|
||||
|
||||
var repo = uow.CreateContainerRepository(ContainerObjectType);
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return OperationStatus.Attempt.NoOperation(evtMsgs);
|
||||
|
||||
if (OnDeletingContainerCancelled(new DeleteEventArgs<EntityContainer>(container, evtMsgs)))
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs)); // causes rollback
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Complete();
|
||||
|
||||
OnDeletedContainer(new DeleteEventArgs<EntityContainer>(container, evtMsgs));
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Audit
|
||||
|
||||
private void Audit(AuditType type, string message, int userId, int objectId)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IAuditRepository>();
|
||||
repo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Xml - Should Move!
|
||||
|
||||
protected abstract void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Containers
|
||||
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<OperationStatusType, EntityContainer>> CreateContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -43,12 +43,8 @@ namespace Umbraco.Core.Services
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
if (SavingContainer.IsRaisedEventCancelled(new SaveEventArgs<EntityContainer>(container, evtMsgs), this))
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs, container); // causes rollback
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Complete();
|
||||
@@ -56,11 +52,11 @@ namespace Umbraco.Core.Services
|
||||
SavedContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, container);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
return OperationStatus.Attempt.Fail<EntityContainer>(evtMsgs, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,6 +67,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repo = uow.CreateRepository<IDataTypeContainerRepository>();
|
||||
var container = repo.Get(containerId);
|
||||
uow.Complete();
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -81,6 +78,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repo = uow.CreateRepository<IDataTypeContainerRepository>();
|
||||
var container = ((EntityContainerRepository)repo).Get(containerId);
|
||||
uow.Complete();
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +88,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IDataTypeContainerRepository>();
|
||||
return ((EntityContainerRepository)repo).Get(name, level);
|
||||
var containers = ((EntityContainerRepository)repo).Get(name, level);
|
||||
uow.Complete();
|
||||
return containers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IDataTypeContainerRepository>();
|
||||
return repo.GetAll(containerIds);
|
||||
var containers = repo.GetAll(containerIds);
|
||||
uow.Complete();
|
||||
return containers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,20 +127,20 @@ namespace Umbraco.Core.Services
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)
|
||||
{
|
||||
var ex = new InvalidOperationException("Not a " + Constants.ObjectTypes.DataTypeGuid + " container.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
return OperationStatus.Attempt.Fail(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (container.HasIdentity && container.IsPropertyDirty("ParentId"))
|
||||
{
|
||||
var ex = new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
return OperationStatus.Attempt.Fail(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (SavingContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -152,7 +154,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0)
|
||||
@@ -162,21 +164,17 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repo = uow.CreateRepository<IDataTypeContainerRepository>();
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
if (container == null) return OperationStatus.Attempt.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
if (DeletingContainer.IsRaisedEventCancelled(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this))
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs)); // causes rollback
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Complete();
|
||||
|
||||
DeletedContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
@@ -193,7 +191,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
return repository.GetByQuery(repository.Query.Where(x => x.Name == name)).FirstOrDefault();
|
||||
var def = repository.GetByQuery(repository.Query.Where(x => x.Name == name)).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
return repository.Get(id);
|
||||
var def = repository.Get(id);
|
||||
uow.Complete();
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,8 +224,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
var query = repository.Query.Where(x => x.Key == id);
|
||||
var definitions = repository.GetByQuery(query);
|
||||
return definitions.FirstOrDefault();
|
||||
var definition = repository.GetByQuery(query).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +242,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
var query = repository.Query.Where(x => x.PropertyEditorAlias == propertyEditorAlias);
|
||||
var definitions = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return definitions;
|
||||
}
|
||||
}
|
||||
@@ -253,7 +257,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var defs = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return defs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +278,7 @@ namespace Umbraco.Core.Services
|
||||
var list = collection.FormatAsDictionary()
|
||||
.Select(x => x.Value.Value)
|
||||
.ToList();
|
||||
uow.Complete();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -286,7 +293,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
return repository.GetPreValuesCollectionByDataTypeId(id);
|
||||
var vals = repository.GetPreValuesCollectionByDataTypeId(id);
|
||||
uow.Complete();
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +309,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
return repository.GetPreValueAsString(id);
|
||||
var val = repository.GetPreValueAsString(id);
|
||||
uow.Complete();
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,9 +323,7 @@ namespace Umbraco.Core.Services
|
||||
new MoveEventArgs<IDataTypeDefinition>(evtMsgs, new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(
|
||||
MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
return OperationStatus.Attempt.Fail(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs);
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IDataTypeDefinition>>();
|
||||
@@ -330,22 +339,20 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
container = containerRepository.Get(parentId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound); // causes rollback
|
||||
}
|
||||
moveInfo.AddRange(repository.Move(toMove, container));
|
||||
uow.Complete();
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
|
||||
return OperationStatus.Attempt.Fail(ex.Operation, evtMsgs);
|
||||
}
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Moved.RaiseEvent(new MoveEventArgs<IDataTypeDefinition>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
return Attempt.Succeed(
|
||||
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
|
||||
return OperationStatus.Attempt.Succeed(MoveOperationStatusType.Success, evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -424,26 +431,21 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
using (var transaction = uow.Database.GetTransaction())
|
||||
var sortOrderObj = uow.Database.ExecuteScalar<object>(
|
||||
"SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = dataTypeId });
|
||||
|
||||
int sortOrder;
|
||||
if (sortOrderObj == null || int.TryParse(sortOrderObj.ToString(), out sortOrder) == false)
|
||||
sortOrder = 1;
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
var sortOrderObj =
|
||||
uow.Database.ExecuteScalar<object>(
|
||||
"SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = dataTypeId });
|
||||
int sortOrder;
|
||||
if (sortOrderObj == null || int.TryParse(sortOrderObj.ToString(), out sortOrder) == false)
|
||||
{
|
||||
sortOrder = 1;
|
||||
}
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
var dto = new DataTypePreValueDto { DataTypeNodeId = dataTypeId, Value = value, SortOrder = sortOrder };
|
||||
uow.Database.Insert(dto);
|
||||
sortOrder++;
|
||||
}
|
||||
|
||||
transaction.Complete();
|
||||
var dto = new DataTypePreValueDto { DataTypeNodeId = dataTypeId, Value = value, SortOrder = sortOrder };
|
||||
uow.Database.Insert(dto);
|
||||
sortOrder++;
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IDomainRepository>();
|
||||
return repo.Exists(domainName);
|
||||
var exists = repo.Exists(domainName);
|
||||
uow.Complete();
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +36,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<IDomain>(domain, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -46,7 +48,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var args = new DeleteEventArgs<IDomain>(domain, false, evtMsgs);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
public IDomain GetByName(string name)
|
||||
@@ -54,7 +56,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDomainRepository>();
|
||||
return repository.GetByName(name);
|
||||
var domain = repository.GetByName(name);
|
||||
uow.Complete();
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +67,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IDomainRepository>();
|
||||
return repo.Get(id);
|
||||
var domain = repo.Get(id);
|
||||
uow.Complete();
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +78,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IDomainRepository>();
|
||||
return repo.GetAll(includeWildcards);
|
||||
var domains = repo.GetAll(includeWildcards);
|
||||
uow.Complete();
|
||||
return domains;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +89,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IDomainRepository>();
|
||||
return repo.GetAssignedDomains(contentId, includeWildcards);
|
||||
var domains = repo.GetAssignedDomains(contentId, includeWildcards);
|
||||
uow.Complete();
|
||||
return domains;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +102,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IDomain>(domainEntity, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -103,7 +113,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<IDomain>(domainEntity, false, evtMsgs), this);
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
@@ -23,20 +23,22 @@ namespace Umbraco.Core.Services
|
||||
|
||||
|
||||
public EntityService(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory,
|
||||
IContentService contentService, IContentTypeService contentTypeService, IMediaService mediaService, IDataTypeService dataTypeService,
|
||||
IMemberService memberService, IMemberTypeService memberTypeService, IRuntimeCacheProvider runtimeCache)
|
||||
IContentService contentService, IContentTypeService contentTypeService,
|
||||
IMediaService mediaService, IMediaTypeService mediaTypeService,
|
||||
IDataTypeService dataTypeService,
|
||||
IMemberService memberService, IMemberTypeService memberTypeService,
|
||||
IRuntimeCacheProvider runtimeCache)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_runtimeCache = runtimeCache;
|
||||
IContentTypeService contentTypeService1 = contentTypeService;
|
||||
|
||||
_supportedObjectTypes = new Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>>
|
||||
{
|
||||
{typeof (IDataTypeDefinition).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.DataType, dataTypeService.GetDataTypeDefinitionById)},
|
||||
{typeof (IContent).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.Document, contentService.GetById)},
|
||||
{typeof (IContentType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.DocumentType, contentTypeService1.GetContentType)},
|
||||
{typeof (IContentType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.DocumentType, contentTypeService.Get)},
|
||||
{typeof (IMedia).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.Media, mediaService.GetById)},
|
||||
{typeof (IMediaType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.MediaType, contentTypeService1.GetMediaType)},
|
||||
{typeof (IMediaType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.MediaType, mediaTypeService.Get)},
|
||||
{typeof (IMember).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.Member, memberService.GetById)},
|
||||
{typeof (IMemberType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.MemberType, memberTypeService.Get)},
|
||||
//{typeof (IUmbracoEntity).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.EntityContainer, id =>
|
||||
@@ -74,6 +76,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var result = _runtimeCache.GetCacheItem<int?>(CacheKeys.IdToKeyCacheKey + key, () =>
|
||||
{
|
||||
int? id;
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
switch (umbracoObjectType)
|
||||
@@ -87,11 +90,12 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
case UmbracoObjectTypes.DocumentTypeContainer:
|
||||
return uow.Database.ExecuteScalar<int?>(
|
||||
id = uow.Database.ExecuteScalar<int?>(
|
||||
uow.Database.Sql()
|
||||
.Select("id")
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(dto => dto.UniqueId == key));
|
||||
break;
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
case UmbracoObjectTypes.MemberGroup:
|
||||
@@ -102,6 +106,8 @@ namespace Umbraco.Core.Services
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
uow.Complete();
|
||||
return id;
|
||||
}
|
||||
});
|
||||
return result.HasValue ? Attempt.Succeed(result.Value) : Attempt<int>.Fail();
|
||||
@@ -119,6 +125,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
Guid? guid;
|
||||
switch (umbracoObjectType)
|
||||
{
|
||||
case UmbracoObjectTypes.Document:
|
||||
@@ -129,11 +136,12 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.DocumentType:
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
return uow.Database.ExecuteScalar<Guid?>(
|
||||
guid = uow.Database.ExecuteScalar<Guid?>(
|
||||
uow.Database.Sql()
|
||||
.Select("uniqueID")
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(dto => dto.NodeId == id));
|
||||
break;
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
case UmbracoObjectTypes.MemberGroup:
|
||||
@@ -144,6 +152,8 @@ namespace Umbraco.Core.Services
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
uow.Complete();
|
||||
return guid;
|
||||
}
|
||||
});
|
||||
return result.HasValue ? Attempt.Succeed(result.Value) : Attempt<Guid>.Fail();
|
||||
@@ -156,7 +166,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.GetByKey(key);
|
||||
var entity = repository.GetByKey(key);
|
||||
uow.Complete();
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +199,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.Get(id);
|
||||
var e = repository.Get(id);
|
||||
uow.Complete();
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +221,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.GetByKey(key, objectTypeId);
|
||||
var entity = repository.GetByKey(key, objectTypeId);
|
||||
uow.Complete();
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +255,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.Get(id, objectTypeId);
|
||||
var e = repository.Get(id, objectTypeId);
|
||||
uow.Complete();
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +290,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.Get(id);
|
||||
var e = repository.Get(id);
|
||||
uow.Complete();
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +321,9 @@ namespace Umbraco.Core.Services
|
||||
if (entity.ParentId == -1 || entity.ParentId == -20 || entity.ParentId == -21)
|
||||
return null;
|
||||
|
||||
return repository.Get(entity.ParentId);
|
||||
var e = repository.Get(entity.ParentId);
|
||||
uow.Complete();
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +343,9 @@ namespace Umbraco.Core.Services
|
||||
return null;
|
||||
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
return repository.Get(entity.ParentId, objectTypeId);
|
||||
var e = repository.Get(entity.ParentId, objectTypeId);
|
||||
uow.Complete();
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +361,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == parentId);
|
||||
var contents = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -356,7 +380,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == parentId);
|
||||
var contents = repository.GetByQuery(query, objectTypeId).ToList(); // run within using!
|
||||
|
||||
uow.Complete();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -375,7 +399,7 @@ namespace Umbraco.Core.Services
|
||||
var pathMatch = entity.Path + ",";
|
||||
var query = repository.Query.Where(x => x.Path.StartsWith(pathMatch) && x.Id != id);
|
||||
var entities = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
@@ -395,7 +419,7 @@ namespace Umbraco.Core.Services
|
||||
var entity = repository.Get(id);
|
||||
var query = repository.Query.Where(x => x.Path.StartsWith(entity.Path) && x.Id != id);
|
||||
var entities = repository.GetByQuery(query, objectTypeId);
|
||||
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
@@ -413,7 +437,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == -1);
|
||||
var entities = repository.GetByQuery(query, objectTypeId);
|
||||
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
@@ -456,7 +480,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.GetAll(objectTypeId, ids);
|
||||
var entities = repository.GetAll(objectTypeId, ids);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +500,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.GetAll(objectTypeId, keys);
|
||||
var entities = repository.GetAll(objectTypeId, keys);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,7 +526,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
return repository.GetAll(objectTypeId, ids);
|
||||
var entities = repository.GetAll(objectTypeId, ids);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +547,9 @@ namespace Umbraco.Core.Services
|
||||
.Where<NodeDto>(x => x.NodeId == id);
|
||||
var nodeObjectTypeId = uow.Database.ExecuteScalar<Guid>(sql);
|
||||
var objectTypeId = nodeObjectTypeId;
|
||||
return UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
var t = UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
uow.Complete();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +568,9 @@ namespace Umbraco.Core.Services
|
||||
.Where<NodeDto>(x => x.UniqueId == key);
|
||||
var nodeObjectTypeId = uow.Database.ExecuteScalar<Guid>(sql);
|
||||
var objectTypeId = nodeObjectTypeId;
|
||||
return UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
var t = UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
uow.Complete();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace Umbraco.Core.Services
|
||||
if (contentType.Level != 1 && masterContentType == null)
|
||||
{
|
||||
//get url encoded folder names
|
||||
var folders = contentTypeService.GetContentTypeContainers(contentType)
|
||||
var folders = contentTypeService.GetContainers(contentType)
|
||||
.OrderBy(x => x.Level)
|
||||
.Select(x => HttpUtility.UrlEncode(x.Name));
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IExternalLoginRepository>();
|
||||
return repo.GetByQuery(repo.Query.Where(x => x.UserId == userId));
|
||||
var ident = repo.GetByQuery(repo.Query.Where(x => x.UserId == userId));
|
||||
uow.Complete();
|
||||
return ident;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +42,10 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IExternalLoginRepository>();
|
||||
return repo.GetByQuery(repo.Query
|
||||
var idents = repo.GetByQuery(repo.Query
|
||||
.Where(x => x.ProviderKey == login.ProviderKey && x.LoginProvider == login.LoginProvider));
|
||||
uow.Complete();
|
||||
return idents;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IStylesheetRepository>();
|
||||
return repository.GetAll(names);
|
||||
var stylesheets = repository.GetAll(names);
|
||||
uow.Complete();
|
||||
return stylesheets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +67,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IStylesheetRepository>();
|
||||
return repository.Get(name);
|
||||
var stylesheet = repository.Get(name);
|
||||
uow.Complete();
|
||||
return stylesheet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,10 +106,14 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IStylesheetRepository>();
|
||||
stylesheet = repository.Get(path);
|
||||
if (stylesheet == null) return;
|
||||
if (stylesheet == null)
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (DeletingStylesheet.IsRaisedEventCancelled(new DeleteEventArgs<Stylesheet>(stylesheet), this))
|
||||
return;
|
||||
return; // causes rollback
|
||||
|
||||
repository.Delete(stylesheet);
|
||||
uow.Complete();
|
||||
@@ -125,7 +133,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IStylesheetRepository>();
|
||||
return repository.ValidateStylesheet(stylesheet);
|
||||
var valid = repository.ValidateStylesheet(stylesheet);
|
||||
uow.Complete();
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +151,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IScriptRepository>();
|
||||
return repository.GetAll(names);
|
||||
var scripts = repository.GetAll(names);
|
||||
uow.Complete();
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +167,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IScriptRepository>();
|
||||
return repository.Get(name);
|
||||
var script = repository.Get(name);
|
||||
uow.Complete();
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,10 +207,14 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IScriptRepository>();
|
||||
script = repository.Get(path);
|
||||
if (script == null) return;
|
||||
if (script == null)
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (DeletingScript.IsRaisedEventCancelled(new DeleteEventArgs<Script>(script), this))
|
||||
return;
|
||||
return; // causes rollback
|
||||
|
||||
repository.Delete(script);
|
||||
uow.Complete();
|
||||
@@ -216,7 +234,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IScriptRepository>();
|
||||
return repository.ValidateScript(script);
|
||||
var valid = repository.ValidateScript(script);
|
||||
uow.Complete();
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +273,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>
|
||||
/// The template created
|
||||
/// </returns>
|
||||
public Attempt<OperationStatus<ITemplate, OperationStatusType>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0)
|
||||
public Attempt<OperationStatus<OperationStatusType, ITemplate>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0)
|
||||
{
|
||||
var template = new Template(contentTypeName,
|
||||
//NOTE: We are NOT passing in the content type alias here, we want to use it's name since we don't
|
||||
@@ -277,7 +297,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<ITemplate>(template, true, evtMsgs, additionalData),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<ITemplate, OperationStatusType>(template, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
return OperationStatus.Attempt.Fail<OperationStatusType, ITemplate>(OperationStatusType.FailedCancelledByEvent, evtMsgs, template);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -290,7 +310,7 @@ namespace Umbraco.Core.Services
|
||||
SavedTemplate.RaiseEvent(new SaveEventArgs<ITemplate>(template, false, evtMsgs), this);
|
||||
Audit(AuditType.Save, "Save Template performed by user", userId, template.Id);
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<ITemplate, OperationStatusType>(template, OperationStatusType.Success, evtMsgs));
|
||||
return OperationStatus.Attempt.Succeed<OperationStatusType, ITemplate>(OperationStatusType.Success, evtMsgs, template);
|
||||
}
|
||||
|
||||
public ITemplate CreateTemplateWithIdentity(string name, string content, ITemplate masterTemplate = null, int userId = 0)
|
||||
@@ -316,7 +336,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetAll(aliases).OrderBy(x => x.Name);
|
||||
var templates = repository.GetAll(aliases).OrderBy(x => x.Name);
|
||||
uow.Complete();
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +351,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetChildren(masterTemplateId).OrderBy(x => x.Name);
|
||||
var templates = repository.GetChildren(masterTemplateId).OrderBy(x => x.Name);
|
||||
uow.Complete();
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +367,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.Get(alias);
|
||||
var template = repository.Get(alias);
|
||||
uow.Complete();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +383,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.Get(id);
|
||||
var template = repository.Get(id);
|
||||
uow.Complete();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +400,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
var query = repository.Query.Where(x => x.Key == id);
|
||||
return repository.GetByQuery(query).SingleOrDefault();
|
||||
var template = repository.GetByQuery(query).SingleOrDefault();
|
||||
uow.Complete();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +411,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetDescendants(alias);
|
||||
var templates = repository.GetDescendants(alias);
|
||||
uow.Complete();
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +427,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetDescendants(masterTemplateId);
|
||||
var templates = repository.GetDescendants(masterTemplateId);
|
||||
uow.Complete();
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +443,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetChildren(alias);
|
||||
var templates = repository.GetChildren(alias);
|
||||
uow.Complete();
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +459,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetChildren(masterTemplateId);
|
||||
var templates = repository.GetChildren(masterTemplateId);
|
||||
uow.Complete();
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +477,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.GetTemplateNode(alias);
|
||||
var template = repository.GetTemplateNode(alias);
|
||||
uow.Complete();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +496,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.FindTemplateInTree(anyNode, alias);
|
||||
var template = repository.FindTemplateInTree(anyNode, alias);
|
||||
uow.Complete();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,7 +563,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.DetermineTemplateRenderingEngine(template);
|
||||
var engine = repository.DetermineTemplateRenderingEngine(template);
|
||||
uow.Complete();
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,10 +581,14 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
template = repository.Get(alias);
|
||||
if (template == null) return;
|
||||
if (template == null)
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (DeletingTemplate.IsRaisedEventCancelled(new DeleteEventArgs<ITemplate>(template), this))
|
||||
return;
|
||||
return; // causes rollback
|
||||
|
||||
repository.Delete(template);
|
||||
uow.Complete();
|
||||
@@ -560,7 +608,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
return repository.ValidateTemplate(template);
|
||||
var valid = repository.ValidateTemplate(template);
|
||||
uow.Complete();
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +659,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IPartialViewRepository>();
|
||||
return repository.Get(path);
|
||||
var view = repository.Get(path);
|
||||
uow.Complete();
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,7 +670,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IPartialViewMacroRepository>();
|
||||
return repository.Get(path);
|
||||
var view = repository.Get(path);
|
||||
uow.Complete();
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,10 +757,13 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreatePartialViewRepository(partialViewType);
|
||||
partialView = repository.Get(path);
|
||||
if (partialView == null)
|
||||
{
|
||||
uow.Complete();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DeletingPartialView.IsRaisedEventCancelled(new DeleteEventArgs<IPartialView>(partialView), this))
|
||||
return false;
|
||||
return false; // causes rollback
|
||||
|
||||
repository.Delete(partialView);
|
||||
uow.Complete();
|
||||
@@ -749,7 +806,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IPartialViewRepository>();
|
||||
return repository.ValidatePartialView(partialView);
|
||||
var valid = repository.ValidatePartialView(partialView);
|
||||
uow.Complete();
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,7 +817,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _fileUowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IPartialViewMacroRepository>();
|
||||
return repository.ValidatePartialView(partialView);
|
||||
var valid = repository.ValidatePartialView(partialView);
|
||||
uow.Complete();
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the ContentTypeService, which is an easy access to operations involving <see cref="IContentType"/>
|
||||
/// Manages <see cref="IContentType"/> objects.
|
||||
/// </summary>
|
||||
public interface IContentTypeService : IService
|
||||
public interface IContentTypeService : IContentTypeServiceBase<IContentType>
|
||||
{
|
||||
int CountContentTypes();
|
||||
int CountMediaTypes();
|
||||
|
||||
/// <summary>
|
||||
/// Validates the composition, if its invalid a list of property type aliases that were duplicated is returned
|
||||
/// </summary>
|
||||
/// <param name="compo"></param>
|
||||
/// <returns></returns>
|
||||
Attempt<string[]> ValidateComposition(IContentTypeComposition compo);
|
||||
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContentTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateMediaTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContentTypeContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0);
|
||||
|
||||
EntityContainer GetContentTypeContainer(int containerId);
|
||||
EntityContainer GetContentTypeContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(int[] containerIds);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(IContentType contentType);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(string folderName, int level);
|
||||
EntityContainer GetMediaTypeContainer(int containerId);
|
||||
EntityContainer GetMediaTypeContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(int[] containerIds);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(string folderName, int level);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(IMediaType mediaType);
|
||||
Attempt<OperationStatus> DeleteMediaTypeContainer(int folderId, int userId = 0);
|
||||
Attempt<OperationStatus> DeleteContentTypeContainer(int containerId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all property type aliases.
|
||||
/// </summary>
|
||||
@@ -55,200 +25,6 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
|
||||
/// </summary>
|
||||
/// <param name="original">
|
||||
/// The content type to copy
|
||||
/// </param>
|
||||
/// <param name="alias">
|
||||
/// The new alias of the content type
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// The new name of the content type
|
||||
/// </param>
|
||||
/// <param name="parentId">
|
||||
/// The parent to copy the content type to, default is -1 (root)
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
IContentType Copy(IContentType original, string alias, string name, int parentId = -1);
|
||||
|
||||
/// <summary>
|
||||
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
|
||||
/// </summary>
|
||||
/// <param name="original">
|
||||
/// The content type to copy
|
||||
/// </param>
|
||||
/// <param name="alias">
|
||||
/// The new alias of the content type
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// The new name of the content type
|
||||
/// </param>
|
||||
/// <param name="parent">
|
||||
/// The parent to copy the content type to
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
IContentType Copy(IContentType original, string alias, string name, IContentType parent);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IContentType"/> object by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IContentType"/> to retrieve</param>
|
||||
/// <returns><see cref="IContentType"/></returns>
|
||||
IContentType GetContentType(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IContentType"/> object by its Alias
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of the <see cref="IContentType"/> to retrieve</param>
|
||||
/// <returns><see cref="IContentType"/></returns>
|
||||
IContentType GetContentType(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IContentType"/> object by its Key
|
||||
/// </summary>
|
||||
/// <param name="id">Alias of the <see cref="IContentType"/> to retrieve</param>
|
||||
/// <returns><see cref="IContentType"/></returns>
|
||||
IContentType GetContentType(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all available <see cref="IContentType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional list of ids</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
IEnumerable<IContentType> GetAllContentTypes(params int[] ids);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all available <see cref="IContentType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional list of ids</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
IEnumerable<IContentType> GetAllContentTypes(IEnumerable<Guid> ids);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of children for a <see cref="IContentType"/> object
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
IEnumerable<IContentType> GetContentTypeChildren(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of children for a <see cref="IContentType"/> object
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
IEnumerable<IContentType> GetContentTypeChildren(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContentType"/> object
|
||||
/// </summary>
|
||||
/// <param name="contentType"><see cref="IContentType"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the ContentType</param>
|
||||
void Save(IContentType contentType, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IContentType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="contentTypes">Collection of <see cref="IContentType"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the ContentTypes</param>
|
||||
void Save(IEnumerable<IContentType> contentTypes, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a single <see cref="IContentType"/> object
|
||||
/// </summary>
|
||||
/// <param name="contentType"><see cref="IContentType"/> to delete</param>
|
||||
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
|
||||
/// <param name="userId">Optional Id of the User deleting the ContentType</param>
|
||||
void Delete(IContentType contentType, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a collection of <see cref="IContentType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="contentTypes">Collection of <see cref="IContentType"/> to delete</param>
|
||||
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
|
||||
/// <param name="userId">Optional Id of the User deleting the ContentTypes</param>
|
||||
void Delete(IEnumerable<IContentType> contentTypes, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMediaType"/> object by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IMediaType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMediaType"/></returns>
|
||||
IMediaType GetMediaType(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMediaType"/> object by its Alias
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of the <see cref="IMediaType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMediaType"/></returns>
|
||||
IMediaType GetMediaType(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMediaType"/> object by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IMediaType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMediaType"/></returns>
|
||||
IMediaType GetMediaType(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all available <see cref="IMediaType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional list of ids</param>
|
||||
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
|
||||
IEnumerable<IMediaType> GetAllMediaTypes(params int[] ids);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all available <see cref="IMediaType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional list of ids</param>
|
||||
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
|
||||
IEnumerable<IMediaType> GetAllMediaTypes(IEnumerable<Guid> ids);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of children for a <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
|
||||
IEnumerable<IMediaType> GetMediaTypeChildren(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of children for a <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
|
||||
IEnumerable<IMediaType> GetMediaTypeChildren(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
/// <param name="mediaType"><see cref="IMediaType"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the MediaType</param>
|
||||
void Save(IMediaType mediaType, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IMediaType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="mediaTypes">Collection of <see cref="IMediaType"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the MediaTypes</param>
|
||||
void Save(IEnumerable<IMediaType> mediaTypes, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a single <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
/// <param name="mediaType"><see cref="IMediaType"/> to delete</param>
|
||||
/// <remarks>Deleting a <see cref="IMediaType"/> will delete all the <see cref="IMedia"/> objects based on this <see cref="IMediaType"/></remarks>
|
||||
/// <param name="userId">Optional Id of the User deleting the MediaType</param>
|
||||
void Delete(IMediaType mediaType, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a collection of <see cref="IMediaType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="mediaTypes">Collection of <see cref="IMediaType"/> to delete</param>
|
||||
/// <remarks>Deleting a <see cref="IMediaType"/> will delete all the <see cref="IMedia"/> objects based on this <see cref="IMediaType"/></remarks>
|
||||
/// <param name="userId">Optional Id of the User deleting the MediaTypes</param>
|
||||
void Delete(IEnumerable<IMediaType> mediaTypes, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Generates the complete (simplified) XML DTD.
|
||||
/// </summary>
|
||||
@@ -260,38 +36,5 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <returns>The DTD as a string</returns>
|
||||
string GetContentTypesDtd();
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IContentType"/> item has any children
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IContentType"/></param>
|
||||
/// <returns>True if the content type has any children otherwise False</returns>
|
||||
bool HasChildren(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IContentType"/> item has any children
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IContentType"/></param>
|
||||
/// <returns>True if the content type has any children otherwise False</returns>
|
||||
bool HasChildren(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IMediaType"/> item has any children
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IMediaType"/></param>
|
||||
/// <returns>True if the media type has any children otherwise False</returns>
|
||||
bool MediaTypeHasChildren(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IMediaType"/> item has any children
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IMediaType"/></param>
|
||||
/// <returns>True if the media type has any children otherwise False</returns>
|
||||
bool MediaTypeHasChildren(Guid id);
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId);
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int containerId);
|
||||
Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId);
|
||||
Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a common base interface for <see cref="IContentTypeService"/>, <see cref="IMediaTypeService"/> and <see cref="IMemberTypeService"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of the item.</typeparam>
|
||||
public interface IContentTypeServiceBase<TItem> : IService
|
||||
where TItem : IContentTypeComposition
|
||||
{
|
||||
TItem Get(int id);
|
||||
TItem Get(Guid key);
|
||||
TItem Get(string alias);
|
||||
|
||||
int Count();
|
||||
|
||||
IEnumerable<TItem> GetAll(params int[] ids);
|
||||
|
||||
IEnumerable<TItem> GetDescendants(int id, bool andSelf); // parent-child axis
|
||||
IEnumerable<TItem> GetComposedOf(int id); // composition axis
|
||||
|
||||
IEnumerable<TItem> GetChildren(int id);
|
||||
bool HasChildren(int id);
|
||||
|
||||
void Save(TItem item, int userId = 0);
|
||||
void Save(IEnumerable<TItem> items, int userId = 0);
|
||||
|
||||
void Delete(TItem item, int userId = 0);
|
||||
void Delete(IEnumerable<TItem> item, int userId = 0);
|
||||
|
||||
|
||||
Attempt<string[]> ValidateComposition(TItem compo);
|
||||
|
||||
|
||||
Attempt<OperationStatus<OperationStatusType, EntityContainer>> CreateContainer(int parentContainerId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0);
|
||||
EntityContainer GetContainer(int containerId);
|
||||
EntityContainer GetContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetContainers(int[] containerIds);
|
||||
IEnumerable<EntityContainer> GetContainers(TItem contentType);
|
||||
IEnumerable<EntityContainer> GetContainers(string folderName, int level);
|
||||
Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0);
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> Move(TItem moving, int containerId);
|
||||
Attempt<OperationStatus<MoveOperationStatusType, TItem>> Copy(TItem copying, int containerId);
|
||||
TItem Copy(TItem original, string alias, string name, int parentId = -1);
|
||||
TItem Copy(TItem original, string alias, string name, TItem parent);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IDataTypeService : IService
|
||||
{
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus<OperationStatusType, EntityContainer>> CreateContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0);
|
||||
EntityContainer GetContainer(int containerId);
|
||||
EntityContainer GetContainer(Guid containerId);
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>
|
||||
/// The template created
|
||||
/// </returns>
|
||||
Attempt<OperationStatus<ITemplate, OperationStatusType>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0);
|
||||
Attempt<OperationStatus<OperationStatusType, ITemplate>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0);
|
||||
|
||||
ITemplate CreateTemplateWithIdentity(string name, string content, ITemplate masterTemplate = null, int userId = 0);
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages <see cref="IMediaType"/> objects.
|
||||
/// </summary>
|
||||
public interface IMediaTypeService : IContentTypeServiceBase<IMediaType>
|
||||
{ }
|
||||
}
|
||||
@@ -4,7 +4,10 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public interface IMemberTypeService : IService
|
||||
/// <summary>
|
||||
/// Manages <see cref="IMemberType"/> objects.
|
||||
/// </summary>
|
||||
public interface IMemberTypeService : IContentTypeServiceBase<IMemberType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a list of all available <see cref="IContentType"/> objects
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="ruleType"></param>
|
||||
/// <param name="ruleValue"></param>
|
||||
/// <returns></returns>
|
||||
Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddRule(IContent content, string ruleType, string ruleValue);
|
||||
Attempt<OperationStatus<OperationStatusType, PublicAccessEntry>> AddRule(IContent content, string ruleType, string ruleValue);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a rule
|
||||
|
||||
@@ -72,9 +72,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var parent = GetDictionaryItemById(parentId.Value);
|
||||
if (parent == null)
|
||||
{
|
||||
throw new ArgumentException("No parent dictionary item was found with id " + parentId.Value);
|
||||
}
|
||||
throw new ArgumentException("No parent dictionary item was found with id " + parentId.Value); // causes rollback
|
||||
}
|
||||
|
||||
item = new DictionaryItem(parentId, key);
|
||||
@@ -90,7 +88,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (SavingDictionaryItem.IsRaisedEventCancelled(new SaveEventArgs<IDictionaryItem>(item), this))
|
||||
return item;
|
||||
return item; // causes rollback
|
||||
|
||||
repository.AddOrUpdate(item);
|
||||
uow.Complete();
|
||||
@@ -116,6 +114,7 @@ namespace Umbraco.Core.Services
|
||||
var item = repository.Get(id);
|
||||
//ensure the lazy Language callback is assigned
|
||||
EnsureDictionaryItemLanguageCallback(item);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -133,6 +132,7 @@ namespace Umbraco.Core.Services
|
||||
var item = repository.Get(id);
|
||||
//ensure the lazy Language callback is assigned
|
||||
EnsureDictionaryItemLanguageCallback(item);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -150,6 +150,7 @@ namespace Umbraco.Core.Services
|
||||
var item = repository.Get(key);
|
||||
//ensure the lazy Language callback is assigned
|
||||
EnsureDictionaryItemLanguageCallback(item);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -168,6 +169,7 @@ namespace Umbraco.Core.Services
|
||||
var items = repository.GetByQuery(query).ToArray();
|
||||
//ensure the lazy Language callback is assigned
|
||||
items.ForEach(EnsureDictionaryItemLanguageCallback);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -185,6 +187,7 @@ namespace Umbraco.Core.Services
|
||||
var items = repository.GetDictionaryItemDescendants(parentId).ToArray();
|
||||
//ensure the lazy Language callback is assigned
|
||||
items.ForEach(EnsureDictionaryItemLanguageCallback);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -202,6 +205,7 @@ namespace Umbraco.Core.Services
|
||||
var items = repository.GetByQuery(query).ToArray();
|
||||
//ensure the lazy Language callback is assigned
|
||||
items.ForEach(EnsureDictionaryItemLanguageCallback);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +220,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDictionaryRepository>();
|
||||
return repository.Get(key) != null;
|
||||
var item = repository.Get(key);
|
||||
uow.Complete();
|
||||
return item != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +282,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ILanguageRepository>();
|
||||
return repository.Get(id);
|
||||
var lang = repository.Get(id);
|
||||
uow.Complete();
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +298,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ILanguageRepository>();
|
||||
return repository.GetByCultureName(cultureName);
|
||||
var lang = repository.GetByCultureName(cultureName);
|
||||
uow.Complete();
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +314,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ILanguageRepository>();
|
||||
return repository.GetByIsoCode(isoCode);
|
||||
var lang = repository.GetByIsoCode(isoCode);
|
||||
uow.Complete();
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,8 +329,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ILanguageRepository>();
|
||||
var languages = repository.GetAll();
|
||||
return languages;
|
||||
var langs = repository.GetAll();
|
||||
uow.Complete();
|
||||
return langs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,10 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMacroRepository>();
|
||||
var q = repository.Query.Where(macro => macro.Alias == alias);
|
||||
return repository.GetByQuery(q).FirstOrDefault();
|
||||
var q = repository.Query.Where(x => x.Alias == alias);
|
||||
var macro = repository.GetByQuery(q).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return macro;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +84,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMacroRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var macros = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return macros;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +95,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMacroRepository>();
|
||||
return repository.Get(id);
|
||||
var macro = repository.Get(id);
|
||||
uow.Complete();
|
||||
return macro;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +240,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.Get(id);
|
||||
var media = repository.Get(id);
|
||||
uow.Complete();
|
||||
return media;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +251,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.Count(contentTypeAlias);
|
||||
var count = repository.Count(contentTypeAlias);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +262,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.CountChildren(parentId, contentTypeAlias);
|
||||
var count = repository.CountChildren(parentId, contentTypeAlias);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +273,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.CountDescendants(parentId, contentTypeAlias);
|
||||
var count = repository.CountDescendants(parentId, contentTypeAlias);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +291,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.GetAll(ids.ToArray());
|
||||
var items = repository.GetAll(ids.ToArray());
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,8 +308,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.Key == key);
|
||||
var contents = repository.GetByQuery(query);
|
||||
return contents.SingleOrDefault();
|
||||
var item = repository.GetByQuery(query).SingleOrDefault();
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,9 +324,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.Level == level && !x.Path.StartsWith("-21"));
|
||||
var query = repository.Query.Where(x => x.Level == level && x.Path.StartsWith("-21") == false);
|
||||
var contents = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -330,7 +341,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.GetByVersion(versionId);
|
||||
var item = repository.GetByVersion(versionId);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,6 +358,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var versions = repository.GetAllVersions(id);
|
||||
uow.Complete();
|
||||
return versions;
|
||||
}
|
||||
}
|
||||
@@ -374,7 +388,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var items = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +406,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == id);
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return medias;
|
||||
}
|
||||
}
|
||||
@@ -436,7 +452,7 @@ namespace Umbraco.Core.Services
|
||||
query.Where(x => x.ParentId == id);
|
||||
|
||||
var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
|
||||
|
||||
uow.Complete();
|
||||
return medias;
|
||||
}
|
||||
}
|
||||
@@ -484,7 +500,7 @@ namespace Umbraco.Core.Services
|
||||
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
|
||||
}
|
||||
var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
|
||||
|
||||
uow.Complete();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -517,7 +533,7 @@ namespace Umbraco.Core.Services
|
||||
var pathMatch = media.Path + ",";
|
||||
var query = repository.Query.Where(x => x.Path.StartsWith(pathMatch) && x.Id != media.Id);
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return medias;
|
||||
}
|
||||
}
|
||||
@@ -558,7 +574,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.ContentTypeId == id);
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return medias;
|
||||
}
|
||||
}
|
||||
@@ -574,7 +590,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == -1);
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return medias;
|
||||
}
|
||||
}
|
||||
@@ -590,7 +606,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.Path.Contains("-21"));
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
uow.Complete();
|
||||
return medias;
|
||||
}
|
||||
}
|
||||
@@ -605,7 +621,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IMediaRepository>();
|
||||
return repo.GetMediaByPath(mediaPath);
|
||||
var item = repo.GetMediaByPath(mediaPath);
|
||||
uow.Complete();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,7 +638,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == id);
|
||||
int count = repository.Count(query);
|
||||
var count = repository.Count(query);
|
||||
uow.Complete();
|
||||
return count > 0;
|
||||
}
|
||||
}
|
||||
@@ -658,7 +677,7 @@ namespace Umbraco.Core.Services
|
||||
media.ParentId = parentId;
|
||||
if (media.Trashed)
|
||||
{
|
||||
media.ChangeTrashedState(false, parentId);
|
||||
((Models.Media)media).ChangeTrashedState(false, parentId);
|
||||
}
|
||||
Save(media, userId,
|
||||
//no events!
|
||||
@@ -716,7 +735,7 @@ namespace Umbraco.Core.Services
|
||||
if (Deleting.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<IMedia>(media, evtMsgs), this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
//Delete children before deleting the 'possible parent'
|
||||
@@ -741,7 +760,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -760,7 +779,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IMedia>(media, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -784,7 +803,7 @@ namespace Umbraco.Core.Services
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false, evtMsgs), this);
|
||||
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -804,7 +823,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IMedia>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,7 +850,7 @@ namespace Umbraco.Core.Services
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(asArray, false, evtMsgs), this);
|
||||
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -858,7 +877,7 @@ namespace Umbraco.Core.Services
|
||||
files = ((MediaRepository)repository).GetFilesInRecycleBinForUploadField();
|
||||
|
||||
if (EmptyingRecycleBin.IsRaisedEventCancelled(new RecycleBinEventArgs(nodeObjectType, entities, files), this))
|
||||
return;
|
||||
return; // causes rollback
|
||||
|
||||
success = repository.EmptyRecycleBin();
|
||||
|
||||
@@ -866,6 +885,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (success)
|
||||
repository.DeleteMediaFiles(files);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
Audit(AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, -21);
|
||||
@@ -893,7 +914,7 @@ namespace Umbraco.Core.Services
|
||||
var contents = repository.GetByQuery(query).ToArray();
|
||||
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMedia>(contents), this))
|
||||
return;
|
||||
return; // causes rollback
|
||||
|
||||
foreach (var content in contents.OrderByDescending(x => x.ParentId))
|
||||
{
|
||||
@@ -911,6 +932,8 @@ namespace Umbraco.Core.Services
|
||||
//Permanently delete the content
|
||||
Delete(content, userId);
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media items by Type performed by user", userId, -1);
|
||||
@@ -933,7 +956,7 @@ namespace Umbraco.Core.Services
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
@@ -952,7 +975,7 @@ namespace Umbraco.Core.Services
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = media.Id });
|
||||
|
||||
media.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
|
||||
((Models.Media)media).ChangeTrashedState(true, Constants.System.RecycleBinMedia);
|
||||
repository.AddOrUpdate(media);
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
@@ -961,7 +984,7 @@ namespace Umbraco.Core.Services
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = descendant.Id });
|
||||
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
((Models.Media)descendant).ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
|
||||
moveInfo.Add(new MoveEventInfo<IMedia>(descendant, descendant.Path, descendant.ParentId));
|
||||
@@ -974,7 +997,7 @@ namespace Umbraco.Core.Services
|
||||
new MoveEventArgs<IMedia>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1138,6 +1161,7 @@ namespace Umbraco.Core.Services
|
||||
repository.RebuildXmlStructures(
|
||||
media => _entitySerializer.Serialize(this, _dataTypeService, _userService, _urlSegmentProviders, media),
|
||||
contentTypeIds: contentTypeIds.Length == 0 ? null : contentTypeIds);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Audit(AuditType.Publish, "MediaService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
|
||||
@@ -1163,7 +1187,7 @@ namespace Umbraco.Core.Services
|
||||
child.Level = parentLevel + 1;
|
||||
if (parentTrashed != child.Trashed)
|
||||
{
|
||||
child.ChangeTrashedState(parentTrashed, child.ParentId);
|
||||
((Models.Media)child).ChangeTrashedState(parentTrashed, child.ParentId);
|
||||
}
|
||||
|
||||
eventInfo.Add(new MoveEventInfo<IMedia>(child, originalPath, child.ParentId));
|
||||
@@ -1197,14 +1221,15 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (mediaTypes.Any() == false)
|
||||
throw new Exception(string.Format("No MediaType matching the passed in Alias: '{0}' was found",
|
||||
mediaTypeAlias));
|
||||
mediaTypeAlias)); // causes rollback
|
||||
|
||||
var mediaType = mediaTypes.First();
|
||||
|
||||
if (mediaType == null)
|
||||
throw new Exception(string.Format("MediaType matching the passed in Alias: '{0}' was null",
|
||||
mediaTypeAlias));
|
||||
mediaTypeAlias)); // causes rollback
|
||||
|
||||
uow.Complete();
|
||||
return mediaType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
internal class MediaTypeService : ContentTypeServiceBase<IMediaTypeRepository, IMediaType, IMediaTypeService>, IMediaTypeService
|
||||
{
|
||||
private IMediaService _mediaService;
|
||||
|
||||
public MediaTypeService(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMediaService mediaService)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_mediaService = mediaService;
|
||||
}
|
||||
|
||||
// beware! order is important to avoid deadlocks
|
||||
protected override int[] ReadLockIds { get; } = { Constants.Locks.MediaTypes };
|
||||
protected override int[] WriteLockIds { get; } = { Constants.Locks.MediaTree, Constants.Locks.MediaTypes };
|
||||
|
||||
// don't remove, will need it later
|
||||
private IMediaService MediaService => _mediaService;
|
||||
//// handle circular dependencies
|
||||
//internal IMediaService MediaService
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (_mediaService == null)
|
||||
// throw new InvalidOperationException("MediaTypeService.MediaService has not been initialized.");
|
||||
// return _mediaService;
|
||||
// }
|
||||
// set { _mediaService = value; }
|
||||
//}
|
||||
|
||||
protected override Guid ContainedObjectType => Constants.ObjectTypes.MediaTypeGuid;
|
||||
|
||||
protected override void DeleteItemsOfTypes(IEnumerable<int> typeIds)
|
||||
{
|
||||
foreach (var typeId in typeIds)
|
||||
MediaService.DeleteMediaOfType(typeId);
|
||||
}
|
||||
|
||||
protected override void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes)
|
||||
{
|
||||
var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray();
|
||||
if (toUpdate.Any() == false) return;
|
||||
|
||||
var mediaService = _mediaService as MediaService;
|
||||
mediaService?.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
return repository.GetAll();
|
||||
var groups = repository.GetAll();
|
||||
uow.Complete();
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +53,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
return repository.Get(id);
|
||||
var group = repository.Get(id);
|
||||
uow.Complete();
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +64,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
return repository.GetByName(name);
|
||||
var group = repository.GetByName(name);
|
||||
uow.Complete();
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,9 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (types.Any() == false)
|
||||
{
|
||||
throw new InvalidOperationException("No member types could be resolved");
|
||||
throw new InvalidOperationException("No member types could be resolved"); // causes rollback
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
if (types.InvariantContains("Member"))
|
||||
{
|
||||
return types.First(x => x.InvariantEquals("Member"));
|
||||
@@ -79,7 +79,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.Exists(username);
|
||||
var exists = repository.Exists(username);
|
||||
uow.Complete();
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +128,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.Exists(id);
|
||||
var exists = repository.Exists(id);
|
||||
uow.Complete();
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +144,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.Get(id);
|
||||
var member = repository.Get(id);
|
||||
uow.Complete();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +164,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
var query = repository.Query.Where(x => x.Key == id);
|
||||
var member = repository.GetByQuery(query).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
@@ -174,6 +181,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
var query = repository.Query.Where(x => x.ContentTypeAlias == memberTypeAlias);
|
||||
var members = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
@@ -191,6 +199,7 @@ namespace Umbraco.Core.Services
|
||||
repository.Get(memberTypeId);
|
||||
var query = repository.Query.Where(x => x.ContentTypeId == memberTypeId);
|
||||
var members = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
@@ -205,7 +214,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.GetByMemberGroup(memberGroupName);
|
||||
var members = repository.GetByMemberGroup(memberGroupName);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +231,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var members = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,13 +253,15 @@ namespace Umbraco.Core.Services
|
||||
var members = repository.GetByQuery(query).ToArray();
|
||||
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMember>(members), this))
|
||||
return;
|
||||
return; // causes rollback
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
//Permantly delete the member
|
||||
Delete(member);
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,10 +310,12 @@ namespace Umbraco.Core.Services
|
||||
query.Where(member => member.Name.SqlWildcard(displayNameToMatch, TextColumnType.NVarchar));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
throw new ArgumentOutOfRangeException("matchType"); // causes rollback
|
||||
}
|
||||
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Name", Direction.Ascending, true);
|
||||
var members = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Name", Direction.Ascending, true);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +366,9 @@ namespace Umbraco.Core.Services
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Email", Direction.Ascending, true);
|
||||
var members = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Email", Direction.Ascending, true);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +419,9 @@ namespace Umbraco.Core.Services
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, true);
|
||||
var members = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, true);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,10 +474,11 @@ namespace Umbraco.Core.Services
|
||||
((Member)x).ShortStringPropertyValue.SqlEndsWith(value, TextColumnType.NVarchar)));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
throw new ArgumentOutOfRangeException("matchType"); // causes rollback
|
||||
}
|
||||
|
||||
var members = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
@@ -513,10 +535,11 @@ namespace Umbraco.Core.Services
|
||||
((Member)x).IntegerPropertyValue <= value);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
throw new ArgumentOutOfRangeException("matchType"); // causes rollback
|
||||
}
|
||||
|
||||
var members = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
@@ -539,6 +562,7 @@ namespace Umbraco.Core.Services
|
||||
((Member)x).BoolPropertyValue == value);
|
||||
|
||||
var members = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
@@ -595,11 +619,12 @@ namespace Umbraco.Core.Services
|
||||
((Member)x).DateTimePropertyValue <= value);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
throw new ArgumentOutOfRangeException("matchType"); // causes rollback
|
||||
}
|
||||
|
||||
//TODO: Since this is by property value, we need a GetByPropertyQuery on the repo!
|
||||
var members = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
@@ -620,6 +645,7 @@ namespace Umbraco.Core.Services
|
||||
repository.RebuildXmlStructures(
|
||||
member => _entitySerializer.Serialize(_dataTypeService, member),
|
||||
contentTypeIds: memberTypeIds.Length == 0 ? null : memberTypeIds);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Audit(AuditType.Publish, "MemberService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
|
||||
@@ -650,7 +676,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
case MemberCountType.All:
|
||||
query = repository.Query;
|
||||
return repository.Count(query);
|
||||
break;
|
||||
case MemberCountType.Online:
|
||||
var fromDate = DateTime.Now.AddMinutes(-Membership.UserIsOnlineTimeWindow);
|
||||
query =
|
||||
@@ -658,24 +684,28 @@ namespace Umbraco.Core.Services
|
||||
x =>
|
||||
((Member)x).PropertyTypeAlias == Constants.Conventions.Member.LastLoginDate &&
|
||||
((Member)x).DateTimePropertyValue > fromDate);
|
||||
return repository.GetCountByQuery(query);
|
||||
break;
|
||||
case MemberCountType.LockedOut:
|
||||
query =
|
||||
repository.Query.Where(
|
||||
x =>
|
||||
((Member)x).PropertyTypeAlias == Constants.Conventions.Member.IsLockedOut &&
|
||||
((Member)x).BoolPropertyValue == true);
|
||||
return repository.GetCountByQuery(query);
|
||||
((Member)x).BoolPropertyValue);
|
||||
break;
|
||||
case MemberCountType.Approved:
|
||||
query =
|
||||
repository.Query.Where(
|
||||
x =>
|
||||
((Member)x).PropertyTypeAlias == Constants.Conventions.Member.IsApproved &&
|
||||
((Member)x).BoolPropertyValue == true);
|
||||
return repository.GetCountByQuery(query);
|
||||
((Member)x).BoolPropertyValue);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("countType");
|
||||
throw new ArgumentOutOfRangeException("countType"); // causes rollback;
|
||||
}
|
||||
|
||||
var count = repository.GetCountByQuery(query);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -702,7 +732,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, true);
|
||||
var members = repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, true);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,12 +761,18 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
IEnumerable<IMember> members;
|
||||
if (memberTypeAlias == null)
|
||||
{
|
||||
return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, filter);
|
||||
members = repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
var query = repository.Query.Where(x => x.ContentTypeAlias == memberTypeAlias);
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, filter);
|
||||
else
|
||||
{
|
||||
var query = repository.Query.Where(x => x.ContentTypeAlias == memberTypeAlias);
|
||||
members = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,7 +787,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.Count(memberTypeAlias);
|
||||
var count = repository.Count(memberTypeAlias);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -927,7 +967,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
var query = repository.Query.Where(x => x.Email.Equals(email));
|
||||
var member = repository.GetByQuery(query).FirstOrDefault();
|
||||
|
||||
uow.Complete();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
@@ -948,7 +988,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
var query = repository.Query.Where(x => x.Username.Equals(username));
|
||||
var member = repository.GetByQuery(query).FirstOrDefault();
|
||||
|
||||
uow.Complete();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
@@ -1060,6 +1100,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
repository.CreateIfNotExists(roleName);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1068,8 +1109,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
var result = repository.GetAll();
|
||||
return result.Select(x => x.Name).Distinct();
|
||||
var result = repository.GetAll().Select(x => x.Name).Distinct();
|
||||
uow.Complete();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1079,7 +1121,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
var result = repository.GetMemberGroupsForMember(memberId);
|
||||
return result.Select(x => x.Name).Distinct();
|
||||
var roles = result.Select(x => x.Name).Distinct();
|
||||
uow.Complete();
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,7 +1133,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
var result = repository.GetMemberGroupsForMember(username);
|
||||
return result.Select(x => x.Name).Distinct();
|
||||
var roles = result.Select(x => x.Name).Distinct();
|
||||
uow.Complete();
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,7 +1144,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.GetByMemberGroup(roleName);
|
||||
var members = repository.GetByMemberGroup(roleName);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1107,7 +1155,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
return repository.FindMembersInRole(roleName, usernameToMatch, matchType);
|
||||
var members = repository.FindMembersInRole(roleName, usernameToMatch, matchType);
|
||||
uow.Complete();
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1134,7 +1184,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
_memberGroupService.Delete(memberGroup);
|
||||
}
|
||||
return found.Any();
|
||||
var deleted = found.Any();
|
||||
uow.Complete();
|
||||
return deleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1149,6 +1201,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
repository.AssignRoles(usernames, roleNames);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1163,6 +1216,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
repository.DissociateRoles(usernames, roleNames);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,6 +1231,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
repository.AssignRoles(memberIds, roleNames);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1191,6 +1246,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
repository.DissociateRoles(memberIds, roleNames);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1209,14 +1265,15 @@ namespace Umbraco.Core.Services
|
||||
if (types.Any() == false)
|
||||
throw new Exception(
|
||||
string.Format("No MemberType matching the passed in Alias: '{0}' was found",
|
||||
memberTypeAlias));
|
||||
memberTypeAlias)); // causes rollback
|
||||
|
||||
var contentType = types.First();
|
||||
|
||||
if (contentType == null)
|
||||
throw new Exception(string.Format("MemberType matching the passed in Alias: '{0}' was null",
|
||||
memberTypeAlias));
|
||||
memberTypeAlias)); // causes rollback
|
||||
|
||||
uow.Complete();
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,218 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public class MemberTypeService : ContentTypeServiceBase, IMemberTypeService
|
||||
internal class MemberTypeService : ContentTypeServiceBase<IMemberTypeRepository, IMemberType, IMemberTypeService>, IMemberTypeService
|
||||
{
|
||||
private readonly IMemberService _memberService;
|
||||
private IMemberService _memberService;
|
||||
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
public MemberTypeService(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberService memberService)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
if (memberService == null) throw new ArgumentNullException("memberService");
|
||||
_memberService = memberService;
|
||||
}
|
||||
|
||||
public IEnumerable<IMemberType> GetAll(params int[] ids)
|
||||
// beware! order is important to avoid deadlocks
|
||||
protected override int[] ReadLockIds { get; } = { Constants.Locks.MemberTypes };
|
||||
protected override int[] WriteLockIds { get; } = { Constants.Locks.MemberTree, Constants.Locks.MemberTypes };
|
||||
|
||||
// don't remove, will need it later
|
||||
private IMemberService MemberService => _memberService;
|
||||
//// handle circular dependencies
|
||||
//internal IMemberService MemberService
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (_memberService == null)
|
||||
// throw new InvalidOperationException("MemberTypeService.MemberService has not been initialized.");
|
||||
// return _memberService;
|
||||
// }
|
||||
// set { _memberService = value; }
|
||||
//}
|
||||
|
||||
protected override Guid ContainedObjectType => Constants.ObjectTypes.MemberTypeGuid;
|
||||
|
||||
protected override void DeleteItemsOfTypes(IEnumerable<int> typeIds)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
return repository.GetAll(ids);
|
||||
}
|
||||
foreach (var typeId in typeIds)
|
||||
MemberService.DeleteMembersOfType(typeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMemberType"/> object by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="IMemberType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMemberType"/></returns>
|
||||
public IMemberType Get(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
return repository.Get(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMemberType"/> object by its Key
|
||||
/// </summary>
|
||||
/// <param name="key">Key of the <see cref="IMemberType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMemberType"/></returns>
|
||||
public IMemberType Get(Guid key)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
return repository.Get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMemberType"/> object by its Alias
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of the <see cref="IMemberType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMemberType"/></returns>
|
||||
public IMemberType Get(string alias)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
return repository.Get(alias);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(IMemberType memberType, int userId = 0)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(memberType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
memberType.CreatorId = userId;
|
||||
repository.AddOrUpdate(memberType);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(memberType);
|
||||
}
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMemberType>(memberType, false), this);
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<IMemberType> memberTypes, int userId = 0)
|
||||
{
|
||||
var asArray = memberTypes.ToArray();
|
||||
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
foreach (var memberType in asArray)
|
||||
{
|
||||
memberType.CreatorId = userId;
|
||||
repository.AddOrUpdate(memberType);
|
||||
}
|
||||
|
||||
//save it all in one go
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
|
||||
}
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMemberType>(asArray, false), this);
|
||||
}
|
||||
|
||||
public void Delete(IMemberType memberType, int userId = 0)
|
||||
{
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(memberType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
_memberService.DeleteMembersOfType(memberType.Id);
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
repository.Delete(memberType);
|
||||
uow.Complete();
|
||||
|
||||
Deleted.RaiseEvent(new DeleteEventArgs<IMemberType>(memberType, false), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(IEnumerable<IMemberType> memberTypes, int userId = 0)
|
||||
{
|
||||
var asArray = memberTypes.ToArray();
|
||||
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
foreach (var contentType in asArray)
|
||||
{
|
||||
_memberService.DeleteMembersOfType(contentType.Id);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IMemberTypeRepository>();
|
||||
foreach (var memberType in asArray)
|
||||
{
|
||||
repository.Delete(memberType);
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Deleted.RaiseEvent(new DeleteEventArgs<IMemberType>(asArray, false), this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called after an IContentType is saved and is used to update the content xml structures in the database
|
||||
/// if they are required to be updated.
|
||||
/// </summary>
|
||||
/// <param name="contentTypes">A tuple of a content type and a boolean indicating if it is new (HasIdentity was false before committing)</param>
|
||||
private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes)
|
||||
protected override void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes)
|
||||
{
|
||||
|
||||
var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray();
|
||||
if (toUpdate.Any() == false) return;
|
||||
|
||||
if (toUpdate.Any())
|
||||
{
|
||||
//if it is a media type then call the rebuilding methods for media
|
||||
var typedMemberService = _memberService as MemberService;
|
||||
if (typedMemberService != null)
|
||||
{
|
||||
typedMemberService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
var memberService = _memberService as MemberService;
|
||||
memberService?.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> Saving;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> Saved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> Deleting;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> Deleted;
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IMigrationEntryRepository>();
|
||||
return repo.FindEntry(migrationName, version);
|
||||
var entry = repo.FindEntry(migrationName, version);
|
||||
uow.Complete();
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +75,9 @@ namespace Umbraco.Core.Services
|
||||
var repo = uow.CreateRepository<IMigrationEntryRepository>();
|
||||
var query = repo.Query
|
||||
.Where(x => x.MigrationName.ToUpper() == migrationName.ToUpper());
|
||||
return repo.GetByQuery(query);
|
||||
var entries = repo.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _uowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
return repository.GetUserNotifications(user);
|
||||
var notifications = repository.GetUserNotifications(user);
|
||||
uow.Complete();
|
||||
return notifications;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +142,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _uowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
return repository.GetEntityNotifications(entity);
|
||||
var notifications = repository.GetEntityNotifications(entity);
|
||||
uow.Complete();
|
||||
return notifications;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +158,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
repository.DeleteNotifications(entity);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +172,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
repository.DeleteNotifications(user);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +187,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
repository.DeleteNotifications(user, entity);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +205,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _uowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
return repository.SetNotifications(user, entity, actions);
|
||||
var notifications = repository.SetNotifications(user, entity, actions);
|
||||
uow.Complete();
|
||||
return notifications;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +223,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _uowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<INotificationsRepository>();
|
||||
return repository.CreateNotification(user, entity, action);
|
||||
var notification = repository.CreateNotification(user, entity, action);
|
||||
uow.Complete();
|
||||
return notification;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +1,210 @@
|
||||
using System;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// The status returned by many of the service methods
|
||||
/// Represents the status of a service operation.
|
||||
/// </summary>
|
||||
public class OperationStatus<TEntity, TStatus> : OperationStatus<TStatus>
|
||||
where TStatus : struct
|
||||
/// <typeparam name="TStatusType">The type of the status type.</typeparam>
|
||||
public class OperationStatus<TStatusType>
|
||||
where TStatusType : struct
|
||||
{
|
||||
public OperationStatus(TEntity entity, TStatus statusType, EventMessages eventMessages) : base(statusType, eventMessages)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus{TStatusType}"/> class with a status and event messages.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
public OperationStatus(TStatusType statusType, EventMessages eventMessages)
|
||||
{
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
public TEntity Entity { get; private set; }
|
||||
|
||||
}
|
||||
|
||||
public class OperationStatus<TStatus>
|
||||
where TStatus : struct
|
||||
{
|
||||
public OperationStatus(TStatus statusType, EventMessages eventMessages)
|
||||
{
|
||||
if (eventMessages == null) throw new ArgumentNullException("eventMessages");
|
||||
if (eventMessages == null) throw new ArgumentNullException(nameof(eventMessages));
|
||||
StatusType = statusType;
|
||||
EventMessages = eventMessages;
|
||||
}
|
||||
|
||||
public TStatus StatusType { get; internal set; }
|
||||
public EventMessages EventMessages { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the status of the operation.
|
||||
/// </summary>
|
||||
/// <remarks>May be internally updated during the operation, but should NOT be updated once the operation has completed.</remarks>
|
||||
public TStatusType StatusType { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event messages produced by the operation.
|
||||
/// </summary>
|
||||
public EventMessages EventMessages { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default operation status
|
||||
/// Represents the status of a service operation that manages (processes, produces...) a value.
|
||||
/// </summary>
|
||||
public class OperationStatus : OperationStatus<OperationStatusType>
|
||||
/// <typeparam name="TStatusType">The type of the status type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
||||
public class OperationStatus<TStatusType, TValue> : OperationStatus<TStatusType>
|
||||
where TStatusType : struct
|
||||
{
|
||||
public OperationStatus(OperationStatusType statusType, EventMessages eventMessages) : base(statusType, eventMessages)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus{TStatusType, TValue}"/> class with a status type and event messages.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
public OperationStatus(TStatusType statusType, EventMessages eventMessages)
|
||||
: base(statusType, eventMessages)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus{TStatusType, TValue}"/> class with a status type, event messages and a value.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
/// <param name="value">The value managed by the operation.</param>
|
||||
public OperationStatus(TStatusType statusType, EventMessages eventMessages, TValue value)
|
||||
: base(statusType, eventMessages)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
|
||||
#region Static Helper methods
|
||||
|
||||
internal static Attempt<OperationStatus> Exception(EventMessages eventMessages, Exception ex)
|
||||
{
|
||||
eventMessages.Add(new EventMessage("", ex.Message, EventMessageType.Error));
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedExceptionThrown, eventMessages), ex);
|
||||
}
|
||||
|
||||
internal static Attempt<OperationStatus> Cancelled(EventMessages eventMessages)
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, eventMessages));
|
||||
}
|
||||
|
||||
internal static Attempt<OperationStatus> Success(EventMessages eventMessages)
|
||||
{
|
||||
return Attempt.Succeed(new OperationStatus(OperationStatusType.Success, eventMessages));
|
||||
}
|
||||
|
||||
internal static Attempt<OperationStatus> NoOperation(EventMessages eventMessages)
|
||||
{
|
||||
return Attempt.Succeed(new OperationStatus(OperationStatusType.NoOperation, eventMessages));
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Gets the value managed by the operation.
|
||||
/// </summary>
|
||||
public TValue Value { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the default operation status.
|
||||
/// </summary>
|
||||
/// <remarks>Also provides static helper methods to create operation statuses.</remarks>
|
||||
public class OperationStatus : OperationStatus<OperationStatusType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus"/> class with a status and event messages.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
public OperationStatus(OperationStatusType statusType, EventMessages eventMessages)
|
||||
: base(statusType, eventMessages)
|
||||
{ }
|
||||
|
||||
internal static class Attempt
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a successful operation attempt.
|
||||
/// </summary>
|
||||
/// <param name="eventMessages">The event messages produced by the operation.</param>
|
||||
/// <returns>A new attempt instance.</returns>
|
||||
public static Attempt<OperationStatus> Succeed(EventMessages eventMessages)
|
||||
{
|
||||
return Core.Attempt.Succeed(new OperationStatus(OperationStatusType.Success, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<OperationStatusType, TValue>> Succeed<TValue>(EventMessages eventMessages)
|
||||
{
|
||||
return Core.Attempt.Succeed(new OperationStatus<OperationStatusType, TValue>(OperationStatusType.Success, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<OperationStatusType, TValue>> Succeed<TValue>(EventMessages eventMessages, TValue value)
|
||||
{
|
||||
return Core.Attempt.Succeed(new OperationStatus<OperationStatusType, TValue>(OperationStatusType.Success, eventMessages, value));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType>> Succeed<TStatusType>(TStatusType statusType, EventMessages eventMessages)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Succeed(new OperationStatus<TStatusType>(statusType, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType, TValue>> Succeed<TStatusType, TValue>(TStatusType statusType, EventMessages eventMessages, TValue value)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Succeed(new OperationStatus<TStatusType, TValue>(statusType, eventMessages, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful operation attempt indicating that nothing was done.
|
||||
/// </summary>
|
||||
/// <param name="eventMessages">The event messages produced by the operation.</param>
|
||||
/// <returns>A new attempt instance.</returns>
|
||||
public static Attempt<OperationStatus> NoOperation(EventMessages eventMessages)
|
||||
{
|
||||
return Core.Attempt.Succeed(new OperationStatus(OperationStatusType.NoOperation, eventMessages));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed operation attempt indicating that the operation has been cancelled.
|
||||
/// </summary>
|
||||
/// <param name="eventMessages">The event messages produced by the operation.</param>
|
||||
/// <returns>A new attempt instance.</returns>
|
||||
public static Attempt<OperationStatus> Cancel(EventMessages eventMessages)
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<OperationStatusType, TValue>> Cancel<TValue>(EventMessages eventMessages)
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<OperationStatusType, TValue>(OperationStatusType.FailedCancelledByEvent, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<OperationStatusType, TValue>> Cancel<TValue>(EventMessages eventMessages, TValue value)
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<OperationStatusType, TValue>(OperationStatusType.FailedCancelledByEvent, eventMessages, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed operation attempt indicating that an exception was thrown during the operation.
|
||||
/// </summary>
|
||||
/// <param name="eventMessages">The event messages produced by the operation.</param>
|
||||
/// <param name="exception">The exception that caused the operation to fail.</param>
|
||||
/// <returns>A new attempt instance.</returns>
|
||||
public static Attempt<OperationStatus> Fail(EventMessages eventMessages, Exception exception)
|
||||
{
|
||||
eventMessages.Add(new EventMessage("", exception.Message, EventMessageType.Error));
|
||||
return Core.Attempt.Fail(new OperationStatus(OperationStatusType.FailedExceptionThrown, eventMessages), exception);
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<OperationStatusType, TValue>> Fail<TValue>(EventMessages eventMessages, Exception exception)
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<OperationStatusType, TValue>(OperationStatusType.FailedExceptionThrown, eventMessages), exception);
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType>> Fail<TStatusType>(TStatusType statusType, EventMessages eventMessages)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<TStatusType>(statusType, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType>> Fail<TStatusType>(TStatusType statusType, EventMessages eventMessages, Exception exception)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<TStatusType>(statusType, eventMessages), exception);
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType, TValue>> Fail<TStatusType, TValue>(TStatusType statusType, EventMessages eventMessages)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<TStatusType, TValue>(statusType, eventMessages));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType, TValue>> Fail<TStatusType, TValue>(TStatusType statusType, EventMessages eventMessages, TValue value)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<TStatusType, TValue>(statusType, eventMessages, value));
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType, TValue>> Fail<TStatusType, TValue>(TStatusType statusType, EventMessages eventMessages, Exception exception)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<TStatusType, TValue>(statusType, eventMessages), exception);
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<TStatusType, TValue>> Fail<TStatusType, TValue>(TStatusType statusType, EventMessages eventMessages, TValue value, Exception exception)
|
||||
where TStatusType : struct
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<TStatusType, TValue>(statusType, eventMessages, value), exception);
|
||||
}
|
||||
|
||||
public static Attempt<OperationStatus<OperationStatusType, TValue>> Cannot<TValue>(EventMessages eventMessages)
|
||||
{
|
||||
return Core.Attempt.Fail(new OperationStatus<OperationStatusType, TValue>(OperationStatusType.FailedCannot, eventMessages));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,70 @@
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// A status type of the result of saving an item
|
||||
/// A value indicating the result of an operation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Anything less than 10 = Success!
|
||||
/// <remarks>Do NOT compare against a hard-coded numeric value to check for success or failure,
|
||||
/// but instead use the IsSuccess() extension method defined below - which should be the unique
|
||||
/// place where the numeric test should take place.
|
||||
/// </remarks>
|
||||
public enum OperationStatusType
|
||||
{
|
||||
/// <summary>
|
||||
/// The saving was successful.
|
||||
/// The operation was successful.
|
||||
/// </summary>
|
||||
Success = 0,
|
||||
|
||||
|
||||
// Values below this value indicate a success, values above it indicate a failure.
|
||||
// This value is considered a failure.
|
||||
//Reserved = 10,
|
||||
|
||||
/// <summary>
|
||||
/// The saving has been cancelled by a 3rd party add-in
|
||||
/// The operation could not complete because of invalid preconditions (eg creating a reference
|
||||
/// to an item that does not exist).
|
||||
/// </summary>
|
||||
FailedCannot = 12,
|
||||
|
||||
/// <summary>
|
||||
/// The operation has been cancelled by an event handler.
|
||||
/// </summary>
|
||||
FailedCancelledByEvent = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Failed, an exception was thrown/handled
|
||||
/// The operation could not complete due to an exception.
|
||||
/// </summary>
|
||||
FailedExceptionThrown = 15,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When no operation is executed because it was not needed (i.e. deleting an item that doesn't exist)
|
||||
/// No operation has been executed because it was not needed (eg deleting an item that doesn't exist).
|
||||
/// </summary>
|
||||
NoOperation = 100,
|
||||
|
||||
//TODO: In the future, we might need to add more operations statuses, potentially like 'FailedByPermissions', etc...
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="OperationStatusType"/> enum.
|
||||
/// </summary>
|
||||
public static class OperationStatusTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the status indicates a success.
|
||||
/// </summary>
|
||||
/// <param name="status">The status.</param>
|
||||
/// <returns>A value indicating whether the status indicates a success.</returns>
|
||||
public static bool IsSuccess(this OperationStatusType status)
|
||||
{
|
||||
return (int) status < 10;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the status indicates a failure.
|
||||
/// </summary>
|
||||
/// <param name="status">The status.</param>
|
||||
/// <returns>A value indicating whether the status indicates a failure.</returns>
|
||||
public static bool IsFailure(this OperationStatusType status)
|
||||
{
|
||||
return (int) status >= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -407,7 +407,7 @@ namespace Umbraco.Core.Services
|
||||
var alias = documentType.Element("Info").Element("Alias").Value;
|
||||
if (_importedContentTypes.ContainsKey(alias) == false)
|
||||
{
|
||||
var contentType = _contentTypeService.GetContentType(alias);
|
||||
var contentType = _contentTypeService.Get(alias);
|
||||
_importedContentTypes.Add(alias, contentType == null
|
||||
? CreateContentTypeFromXml(documentType)
|
||||
: UpdateContentTypeFromXml(documentType, contentType));
|
||||
@@ -470,18 +470,18 @@ namespace Umbraco.Core.Services
|
||||
var folders = foldersAttribute.Value.Split('/');
|
||||
var rootFolder = HttpUtility.UrlDecode(folders[0]);
|
||||
//level 1 = root level folders, there can only be one with the same name
|
||||
var current = _contentTypeService.GetContentTypeContainers(rootFolder, 1).FirstOrDefault();
|
||||
var current = _contentTypeService.GetContainers(rootFolder, 1).FirstOrDefault();
|
||||
|
||||
if (current == null)
|
||||
{
|
||||
var tryCreateFolder = _contentTypeService.CreateContentTypeContainer(-1, rootFolder);
|
||||
var tryCreateFolder = _contentTypeService.CreateContainer(-1, rootFolder);
|
||||
if (tryCreateFolder == false)
|
||||
{
|
||||
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
var rootFolderId = tryCreateFolder.Result.Entity.Id;
|
||||
current = _contentTypeService.GetContentTypeContainer(rootFolderId);
|
||||
var rootFolderId = tryCreateFolder.Result.Value.Id;
|
||||
current = _contentTypeService.GetContainer(rootFolderId);
|
||||
}
|
||||
|
||||
importedFolders.Add(alias, current.Id);
|
||||
@@ -505,16 +505,16 @@ namespace Umbraco.Core.Services
|
||||
if (found)
|
||||
{
|
||||
var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id;
|
||||
return _contentTypeService.GetContentTypeContainer(containerId);
|
||||
return _contentTypeService.GetContainer(containerId);
|
||||
}
|
||||
|
||||
var tryCreateFolder = _contentTypeService.CreateContentTypeContainer(current.Id, folderName);
|
||||
var tryCreateFolder = _contentTypeService.CreateContainer(current.Id, folderName);
|
||||
if (tryCreateFolder == false)
|
||||
{
|
||||
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
return _contentTypeService.GetContentTypeContainer(tryCreateFolder.Result.Entity.Id);
|
||||
return _contentTypeService.GetContainer(tryCreateFolder.Result.Value.Id);
|
||||
}
|
||||
|
||||
private IContentType CreateContentTypeFromXml(XElement documentType)
|
||||
@@ -529,7 +529,7 @@ namespace Umbraco.Core.Services
|
||||
var masterAlias = masterElement.Value;
|
||||
parent = _importedContentTypes.ContainsKey(masterAlias)
|
||||
? _importedContentTypes[masterAlias]
|
||||
: _contentTypeService.GetContentType(masterAlias);
|
||||
: _contentTypeService.Get(masterAlias);
|
||||
}
|
||||
|
||||
var alias = infoElement.Element("Alias").Value;
|
||||
@@ -570,7 +570,7 @@ namespace Umbraco.Core.Services
|
||||
var masterAlias = masterElement.Value;
|
||||
IContentType parent = _importedContentTypes.ContainsKey(masterAlias)
|
||||
? _importedContentTypes[masterAlias]
|
||||
: _contentTypeService.GetContentType(masterAlias);
|
||||
: _contentTypeService.Get(masterAlias);
|
||||
|
||||
contentType.SetLazyParentId(new Lazy<int>(() => parent.Id));
|
||||
}
|
||||
@@ -587,7 +587,7 @@ namespace Umbraco.Core.Services
|
||||
var compositionAlias = composition.Value;
|
||||
var compositionContentType = _importedContentTypes.ContainsKey(compositionAlias)
|
||||
? _importedContentTypes[compositionAlias]
|
||||
: _contentTypeService.GetContentType(compositionAlias);
|
||||
: _contentTypeService.Get(compositionAlias);
|
||||
var added = contentType.AddContentType(compositionContentType);
|
||||
}
|
||||
}
|
||||
@@ -791,14 +791,15 @@ namespace Umbraco.Core.Services
|
||||
if (types.Any() == false)
|
||||
throw new Exception(
|
||||
string.Format("No ContentType matching the passed in Alias: '{0}' was found",
|
||||
contentTypeAlias));
|
||||
contentTypeAlias)); // causes rollback
|
||||
|
||||
var contentType = types.FirstOrDefault();
|
||||
|
||||
if (contentType == null)
|
||||
throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null",
|
||||
contentTypeAlias));
|
||||
contentTypeAlias)); // causes rollback
|
||||
|
||||
uow.Complete();
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -953,7 +954,7 @@ namespace Umbraco.Core.Services
|
||||
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
|
||||
current = _dataTypeService.GetContainer(tryCreateFolder.Result.Value.Id);
|
||||
}
|
||||
|
||||
importedFolders.Add(name, current.Id);
|
||||
@@ -986,7 +987,7 @@ namespace Umbraco.Core.Services
|
||||
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
|
||||
return _dataTypeService.GetContainer(tryCreateFolder.Result.Value.Id);
|
||||
}
|
||||
|
||||
private void SavePrevaluesFromXml(List<IDataTypeDefinition> dataTypes, IEnumerable<XElement> dataTypeElements)
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -28,7 +25,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<IPublicAccessRepository>();
|
||||
return repo.GetAll();
|
||||
var entries = repo.GetAll();
|
||||
uow.Complete();
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +75,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
//This will retrieve from cache!
|
||||
var entries = repo.GetAll().ToArray();
|
||||
uow.Complete();
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
@@ -116,7 +116,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="ruleType"></param>
|
||||
/// <param name="ruleValue"></param>
|
||||
/// <returns></returns>
|
||||
public Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddRule(IContent content, string ruleType, string ruleValue)
|
||||
public Attempt<OperationStatus<OperationStatusType, PublicAccessEntry>> AddRule(IContent content, string ruleType, string ruleValue)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
PublicAccessEntry entry;
|
||||
@@ -126,7 +126,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
entry = repo.GetAll().FirstOrDefault(x => x.ProtectedNodeId == content.Id);
|
||||
if (entry == null)
|
||||
return Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>>.Fail();
|
||||
return OperationStatus.Attempt.Cannot<PublicAccessEntry>(evtMsgs); // causes rollback
|
||||
|
||||
var existingRule = entry.Rules.FirstOrDefault(x => x.RuleType == ruleType && x.RuleValue == ruleValue);
|
||||
if (existingRule == null)
|
||||
@@ -136,17 +136,11 @@ namespace Umbraco.Core.Services
|
||||
else
|
||||
{
|
||||
//If they are both the same already then there's nothing to update, exit
|
||||
return Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>>.Succeed(
|
||||
new OperationStatus<PublicAccessEntry, OperationStatusType>(entry, OperationStatusType.Success, evtMsgs));
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, entry);
|
||||
}
|
||||
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>>.Fail(
|
||||
new OperationStatus<PublicAccessEntry, OperationStatusType>(entry, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs), this))
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs, entry); // causes rollback
|
||||
|
||||
repo.AddOrUpdate(entry);
|
||||
|
||||
@@ -154,8 +148,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>>.Succeed(
|
||||
new OperationStatus<PublicAccessEntry, OperationStatusType>(entry, OperationStatusType.Success, evtMsgs));
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, entry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -173,22 +166,22 @@ namespace Umbraco.Core.Services
|
||||
var repo = uow.CreateRepository<IPublicAccessRepository>();
|
||||
|
||||
entry = repo.GetAll().FirstOrDefault(x => x.ProtectedNodeId == content.Id);
|
||||
if (entry == null) return Attempt<OperationStatus>.Fail();
|
||||
if (entry == null) return Attempt<OperationStatus>.Fail(); // causes rollback
|
||||
|
||||
var existingRule = entry.Rules.FirstOrDefault(x => x.RuleType == ruleType && x.RuleValue == ruleValue);
|
||||
if (existingRule == null) return Attempt<OperationStatus>.Fail();
|
||||
if (existingRule == null) return Attempt<OperationStatus>.Fail(); // causes rollback
|
||||
|
||||
entry.RemoveRule(existingRule);
|
||||
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs), this))
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs); // causes rollback
|
||||
|
||||
repo.AddOrUpdate(entry);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -202,7 +195,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -213,7 +206,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -227,7 +220,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
@@ -238,7 +231,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Deleted.RaiseEvent(new DeleteEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,7 +33,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
return repository.Get(id);
|
||||
var relation = repository.Get(id);
|
||||
uow.Complete();
|
||||
return relation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +49,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationTypeRepository>();
|
||||
return repository.Get(id);
|
||||
var type = repository.Get(id);
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +66,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationTypeRepository>();
|
||||
var query = repository.Query.Where(x => x.Alias == alias);
|
||||
return repository.GetByQuery(query).FirstOrDefault();
|
||||
var type = repository.GetByQuery(query).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +82,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var relations = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +109,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.RelationTypeId == relationTypeId);
|
||||
return repository.GetByQuery(query);
|
||||
var relations = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +125,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationTypeRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var types = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +142,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == id);
|
||||
return repository.GetByQuery(query);
|
||||
var relations = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +180,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.ChildId == id);
|
||||
return repository.GetByQuery(query);
|
||||
var relations = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +219,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.ChildId == id || x.ParentId == id);
|
||||
return repository.GetByQuery(query);
|
||||
var relations = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,11 +233,17 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var rtQuery = repository.Query.Where(x => x.Alias == relationTypeAlias);
|
||||
var relationType = repository.GetByQuery(rtQuery).FirstOrDefault();
|
||||
if (relationType == null) return Enumerable.Empty<IRelation>();
|
||||
if (relationType == null)
|
||||
{
|
||||
uow.Complete();
|
||||
return Enumerable.Empty<IRelation>();
|
||||
}
|
||||
|
||||
var relationRepo = uow.CreateRepository<IRelationRepository>();
|
||||
var query = relationRepo.Query.Where(x => (x.ChildId == id || x.ParentId == id) && x.RelationTypeId == relationType.Id);
|
||||
return relationRepo.GetByQuery(query);
|
||||
var relations = relationRepo.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +264,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
relationTypeIds = relationTypes.Select(x => x.Id).ToList();
|
||||
}
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
if (relationTypeIds == null)
|
||||
@@ -265,6 +290,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
relationTypeIds = relationTypes.Select(x => x.Id).ToList();
|
||||
}
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
if (relationTypeIds == null)
|
||||
@@ -284,7 +310,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.RelationTypeId == relationTypeId);
|
||||
return repository.GetByQuery(query);
|
||||
var relations = repository.GetByQuery(query);
|
||||
uow.Complete();
|
||||
return relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,7 +477,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.RelationTypeId == relationType.Id);
|
||||
return repository.GetByQuery(query).Any();
|
||||
var has = repository.GetByQuery(query).Any();
|
||||
uow.Complete();
|
||||
return has;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +494,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == id || x.ChildId == id);
|
||||
return repository.GetByQuery(query).Any();
|
||||
var isRelated = repository.GetByQuery(query).Any();
|
||||
uow.Complete();
|
||||
return isRelated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +512,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == parentId && x.ChildId == childId);
|
||||
return repository.GetByQuery(query).Any();
|
||||
var areRelated = repository.GetByQuery(query).Any();
|
||||
uow.Complete();
|
||||
return areRelated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +548,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
var query = repository.Query.Where(x => x.ParentId == parentId && x.ChildId == childId && x.RelationTypeId == relationType.Id);
|
||||
return repository.GetByQuery(query).Any();
|
||||
var areRelated = repository.GetByQuery(query).Any();
|
||||
uow.Complete();
|
||||
return areRelated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,6 +689,7 @@ namespace Umbraco.Core.Services
|
||||
var query = repository.Query.Where(x => x.RelationTypeId == id);
|
||||
relations.AddRange(repository.GetByQuery(query).ToList());
|
||||
}
|
||||
uow.Complete();
|
||||
}
|
||||
return relations;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(Constants.Locks.Servers);
|
||||
var repo = uow.CreateRepository<IServerRegistrationRepository>();
|
||||
repo.WriteLockServers();
|
||||
|
||||
((ServerRegistrationRepository) repo).ReloadCache(); // ensure we have up-to-date cache
|
||||
|
||||
@@ -103,8 +103,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(Constants.Locks.Servers);
|
||||
var repo = uow.CreateRepository<IServerRegistrationRepository>();
|
||||
repo.WriteLockServers();
|
||||
|
||||
((ServerRegistrationRepository) repo).ReloadCache(); // ensure we have up-to-date cache
|
||||
|
||||
@@ -125,10 +125,10 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(Constants.Locks.Servers);
|
||||
var repo = uow.CreateRepository<IServerRegistrationRepository>();
|
||||
repo.WriteLockServers();
|
||||
|
||||
repo.DeactiveStaleServers(staleTimeout);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,10 +165,11 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.Servers);
|
||||
var repo = uow.CreateRepository<IServerRegistrationRepository>();
|
||||
repo.ReadLockServers();
|
||||
|
||||
return repo.GetAll().Where(x => x.IsActive).ToArray(); // fast, cached
|
||||
var servers = repo.GetAll().Where(x => x.IsActive).ToArray(); // fast, cached
|
||||
uow.Complete();
|
||||
return servers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Umbraco.Core.Services
|
||||
private readonly Lazy<IMemberService> _memberService;
|
||||
private readonly Lazy<IMediaService> _mediaService;
|
||||
private readonly Lazy<IContentTypeService> _contentTypeService;
|
||||
private readonly Lazy<IMediaTypeService> _mediaTypeService;
|
||||
private readonly Lazy<IDataTypeService> _dataTypeService;
|
||||
private readonly Lazy<IFileService> _fileService;
|
||||
private readonly Lazy<ILocalizationService> _localizationService;
|
||||
@@ -38,7 +39,7 @@ namespace Umbraco.Core.Services
|
||||
/// Initializes a new instance of the <see cref="ServiceContext"/> class with lazy services.
|
||||
/// </summary>
|
||||
/// <remarks>Used by IoC. Note that LightInject will favor lazy args when picking a constructor.</remarks>
|
||||
public ServiceContext(Lazy<IMigrationEntryService> migrationEntryService, Lazy<IPublicAccessService> publicAccessService, Lazy<ITaskService> taskService, Lazy<IDomainService> domainService, Lazy<IAuditService> auditService, Lazy<ILocalizedTextService> localizedTextService, Lazy<ITagService> tagService, Lazy<IContentService> contentService, Lazy<IUserService> userService, Lazy<IMemberService> memberService, Lazy<IMediaService> mediaService, Lazy<IContentTypeService> contentTypeService, Lazy<IDataTypeService> dataTypeService, Lazy<IFileService> fileService, Lazy<ILocalizationService> localizationService, Lazy<IPackagingService> packagingService, Lazy<IServerRegistrationService> serverRegistrationService, Lazy<IEntityService> entityService, Lazy<IRelationService> relationService, Lazy<IApplicationTreeService> treeService, Lazy<ISectionService> sectionService, Lazy<IMacroService> macroService, Lazy<IMemberTypeService> memberTypeService, Lazy<IMemberGroupService> memberGroupService, Lazy<INotificationService> notificationService, Lazy<IExternalLoginService> externalLoginService)
|
||||
public ServiceContext(Lazy<IMigrationEntryService> migrationEntryService, Lazy<IPublicAccessService> publicAccessService, Lazy<ITaskService> taskService, Lazy<IDomainService> domainService, Lazy<IAuditService> auditService, Lazy<ILocalizedTextService> localizedTextService, Lazy<ITagService> tagService, Lazy<IContentService> contentService, Lazy<IUserService> userService, Lazy<IMemberService> memberService, Lazy<IMediaService> mediaService, Lazy<IContentTypeService> contentTypeService, Lazy<IMediaTypeService> mediaTypeService, Lazy<IDataTypeService> dataTypeService, Lazy<IFileService> fileService, Lazy<ILocalizationService> localizationService, Lazy<IPackagingService> packagingService, Lazy<IServerRegistrationService> serverRegistrationService, Lazy<IEntityService> entityService, Lazy<IRelationService> relationService, Lazy<IApplicationTreeService> treeService, Lazy<ISectionService> sectionService, Lazy<IMacroService> macroService, Lazy<IMemberTypeService> memberTypeService, Lazy<IMemberGroupService> memberGroupService, Lazy<INotificationService> notificationService, Lazy<IExternalLoginService> externalLoginService)
|
||||
{
|
||||
_migrationEntryService = migrationEntryService;
|
||||
_publicAccessService = publicAccessService;
|
||||
@@ -52,6 +53,7 @@ namespace Umbraco.Core.Services
|
||||
_memberService = memberService;
|
||||
_mediaService = mediaService;
|
||||
_contentTypeService = contentTypeService;
|
||||
_mediaTypeService = mediaTypeService;
|
||||
_dataTypeService = dataTypeService;
|
||||
_fileService = fileService;
|
||||
_localizationService = localizationService;
|
||||
@@ -76,6 +78,7 @@ namespace Umbraco.Core.Services
|
||||
IContentService contentService = null,
|
||||
IMediaService mediaService = null,
|
||||
IContentTypeService contentTypeService = null,
|
||||
IMediaTypeService mediaTypeService = null,
|
||||
IDataTypeService dataTypeService = null,
|
||||
IFileService fileService = null,
|
||||
ILocalizationService localizationService = null,
|
||||
@@ -109,6 +112,7 @@ namespace Umbraco.Core.Services
|
||||
if (contentService != null) _contentService = new Lazy<IContentService>(() => contentService);
|
||||
if (mediaService != null) _mediaService = new Lazy<IMediaService>(() => mediaService);
|
||||
if (contentTypeService != null) _contentTypeService = new Lazy<IContentTypeService>(() => contentTypeService);
|
||||
if (mediaTypeService != null) _mediaTypeService = new Lazy<IMediaTypeService>(() => mediaTypeService);
|
||||
if (dataTypeService != null) _dataTypeService = new Lazy<IDataTypeService>(() => dataTypeService);
|
||||
if (fileService != null) _fileService = new Lazy<IFileService>(() => fileService);
|
||||
if (localizationService != null) _localizationService = new Lazy<ILocalizationService>(() => localizationService);
|
||||
@@ -198,6 +202,11 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public IContentTypeService ContentTypeService => _contentTypeService.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IMediaTypeService"/>
|
||||
/// </summary>
|
||||
public IMediaTypeService MediaTypeService => _mediaTypeService.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IDataTypeService"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -29,7 +29,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntityById(id);
|
||||
var entity = repository.GetTaggedEntityById(id);
|
||||
uow.Complete();
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +40,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntityByKey(key);
|
||||
var entity = repository.GetTaggedEntityByKey(key);
|
||||
uow.Complete();
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +57,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Content, tagGroup);
|
||||
var entities = repository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Content, tagGroup);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +75,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntitiesByTag(TaggableObjectTypes.Content, tag, tagGroup);
|
||||
var entities = repository.GetTaggedEntitiesByTag(TaggableObjectTypes.Content, tag, tagGroup);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +92,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Media, tagGroup);
|
||||
var entities = repository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Media, tagGroup);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +110,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntitiesByTag(TaggableObjectTypes.Media, tag, tagGroup);
|
||||
var entities = repository.GetTaggedEntitiesByTag(TaggableObjectTypes.Media, tag, tagGroup);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +127,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Member, tagGroup);
|
||||
var entities = repository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Member, tagGroup);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +145,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTaggedEntitiesByTag(TaggableObjectTypes.Member, tag, tagGroup);
|
||||
var entities = repository.GetTaggedEntitiesByTag(TaggableObjectTypes.Member, tag, tagGroup);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +161,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForEntityType(TaggableObjectTypes.All, tagGroup);
|
||||
var tags = repository.GetTagsForEntityType(TaggableObjectTypes.All, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +179,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForEntityType(TaggableObjectTypes.Content, tagGroup);
|
||||
var tags = repository.GetTagsForEntityType(TaggableObjectTypes.Content, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +197,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForEntityType(TaggableObjectTypes.Media, tagGroup);
|
||||
var tags = repository.GetTagsForEntityType(TaggableObjectTypes.Media, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +215,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForEntityType(TaggableObjectTypes.Member, tagGroup);
|
||||
var tags = repository.GetTagsForEntityType(TaggableObjectTypes.Member, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +235,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup);
|
||||
var tags = repository.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +254,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForEntity(contentId, tagGroup);
|
||||
var tags = repository.GetTagsForEntity(contentId, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +274,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup);
|
||||
var tags = repository.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +293,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<ITagRepository>();
|
||||
return repository.GetTagsForEntity(contentId, tagGroup);
|
||||
var tags = repository.GetTagsForEntity(contentId, tagGroup);
|
||||
uow.Complete();
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<ITaskTypeRepository>();
|
||||
return repo.GetByQuery(repo.Query.Where(type => type.Alias == taskTypeAlias)).FirstOrDefault();
|
||||
var type = repo.GetByQuery(repo.Query.Where(x => x.Alias == taskTypeAlias)).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +34,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<ITaskTypeRepository>();
|
||||
return repo.Get(id);
|
||||
var type = repo.Get(id);
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +65,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<ITaskTypeRepository>();
|
||||
return repo.GetAll();
|
||||
var types = repo.GetAll();
|
||||
uow.Complete();
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +77,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<ITaskRepository>();
|
||||
return repo.GetTasks(itemId, assignedUser, ownerUser, taskTypeAlias);
|
||||
var tasks = repo.GetTasks(itemId, assignedUser, ownerUser, taskTypeAlias);
|
||||
uow.Complete();
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +112,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = uow.CreateRepository<ITaskRepository>();
|
||||
return repo.Get(id);
|
||||
var task = repo.Get(id);
|
||||
uow.Complete();
|
||||
return task;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,11 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (types.Any() == false)
|
||||
{
|
||||
throw new EntityNotFoundException("No member types could be resolved");
|
||||
throw new EntityNotFoundException("No member types could be resolved"); // causes rollback
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
|
||||
if (types.InvariantContains("writer"))
|
||||
{
|
||||
return types.First(x => x.InvariantEquals("writer"));
|
||||
@@ -78,7 +80,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
return repository.Exists(username);
|
||||
var exists = repository.Exists(username);
|
||||
uow.Complete();
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +140,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
var loginExists = uow.Database.ExecuteScalar<int>("SELECT COUNT(id) FROM umbracoUser WHERE userLogin = @Login", new { Login = username }) != 0;
|
||||
if (loginExists)
|
||||
throw new ArgumentException("Login already exists");
|
||||
throw new ArgumentException("Login already exists"); // causes rollback
|
||||
|
||||
user = new User(userType)
|
||||
{
|
||||
@@ -177,8 +181,8 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
var user = repository.Get((int)id);
|
||||
|
||||
var user = repository.Get(id);
|
||||
uow.Complete();
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -211,7 +215,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
var query = repository.Query.Where(x => x.Email.Equals(email));
|
||||
var user = repository.GetByQuery(query).FirstOrDefault();
|
||||
|
||||
uow.Complete();
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -228,6 +232,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
var query = repository.Query.Where(x => x.Username.Equals(username));
|
||||
var user = repository.GetByQuery(query).FirstOrDefault();
|
||||
uow.Complete();
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -322,9 +327,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
repository.AddOrUpdate(entity);
|
||||
try
|
||||
{
|
||||
repository.AddOrUpdate(entity);
|
||||
uow.Complete();
|
||||
}
|
||||
catch (DbException ex)
|
||||
@@ -407,7 +412,9 @@ namespace Umbraco.Core.Services
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Email);
|
||||
var users = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Email);
|
||||
uow.Complete();
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,7 +455,9 @@ namespace Umbraco.Core.Services
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Username);
|
||||
var users = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Username);
|
||||
uow.Complete();
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +482,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
case MemberCountType.All:
|
||||
query = repository.Query;
|
||||
return repository.Count(query);
|
||||
break;
|
||||
case MemberCountType.Online:
|
||||
throw new NotImplementedException();
|
||||
//var fromDate = DateTime.Now.AddMinutes(-Membership.UserIsOnlineTimeWindow);
|
||||
@@ -484,18 +493,18 @@ namespace Umbraco.Core.Services
|
||||
// ((Member)x).DateTimePropertyValue > fromDate);
|
||||
//return repository.GetCountByQuery(query);
|
||||
case MemberCountType.LockedOut:
|
||||
query =
|
||||
repository.Query.Where(
|
||||
x => x.IsLockedOut);
|
||||
return repository.GetCountByQuery(query);
|
||||
query = repository.Query.Where(x => x.IsLockedOut);
|
||||
break;
|
||||
case MemberCountType.Approved:
|
||||
query =
|
||||
repository.Query.Where(
|
||||
x => x.IsApproved);
|
||||
return repository.GetCountByQuery(query);
|
||||
query = repository.Query.Where(x => x.IsApproved);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("countType");
|
||||
}
|
||||
|
||||
var count = repository.GetCountByQuery(query);
|
||||
uow.Complete();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +520,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, member => member.Username);
|
||||
var users = repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, member => member.Username);
|
||||
uow.Complete();
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,7 +562,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
return repository.Get(id);
|
||||
var user = repository.Get(id);
|
||||
uow.Complete();
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,6 +581,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
repository.ReplaceUserPermissions(userId, permissions, entityIds);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,6 +597,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
repository.AssignUserPermission(userId, permission, entityIds);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +611,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserTypeRepository>();
|
||||
return repository.GetAll(ids);
|
||||
var types = repository.GetAll(ids);
|
||||
uow.Complete();
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,8 +628,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserTypeRepository>();
|
||||
var query = repository.QueryFactory.Create<IUserType>().Where(x => x.Alias == alias);
|
||||
var contents = repository.GetByQuery(query);
|
||||
return contents.SingleOrDefault();
|
||||
var type = repository.GetByQuery(query).SingleOrDefault();
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +644,9 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserTypeRepository>();
|
||||
return repository.Get(id);
|
||||
var type = repository.Get(id);
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,8 +661,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserTypeRepository>();
|
||||
var query = repository.QueryFactory.Create<IUserType>().Where(x => x.Name == name);
|
||||
var contents = repository.GetByQuery(query);
|
||||
return contents.SingleOrDefault();
|
||||
var type = repository.GetByQuery(query).SingleOrDefault();
|
||||
uow.Complete();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,23 +784,16 @@ namespace Umbraco.Core.Services
|
||||
if (id == -1 && user.DefaultPermissions.Any() == false)
|
||||
{
|
||||
// exception to everything. If default cruds is empty and we're on root node; allow browse of root node
|
||||
result.Add(
|
||||
new EntityPermission(
|
||||
user.Id,
|
||||
id,
|
||||
user.DefaultPermissions.ToArray()));
|
||||
result.Add(new EntityPermission(user.Id, id, user.DefaultPermissions.ToArray()));
|
||||
}
|
||||
else
|
||||
{
|
||||
//use the user's user type permissions
|
||||
result.Add(
|
||||
new EntityPermission(
|
||||
user.Id,
|
||||
id,
|
||||
user.DefaultPermissions.ToArray()));
|
||||
result.Add(new EntityPermission(user.Id, id, user.DefaultPermissions.ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
<Compile Include="ApplicationEventHandler.cs" />
|
||||
<Compile Include="AssemblyExtensions.cs" />
|
||||
<Compile Include="AsyncLock.cs" />
|
||||
<Compile Include="Attempt{T}.cs" />
|
||||
<Compile Include="AttemptOfT.cs" />
|
||||
<Compile Include="CacheHelper.cs" />
|
||||
<Compile Include="Cache\CacheKeys.cs" />
|
||||
<Compile Include="Cache\CacheProviderExtensions.cs" />
|
||||
@@ -356,6 +356,7 @@
|
||||
<Compile Include="Models\ContentTypeAvailableCompositionsResult.cs" />
|
||||
<Compile Include="Models\ContentTypeAvailableCompositionsResults.cs" />
|
||||
<Compile Include="Models\EntityContainer.cs" />
|
||||
<Compile Include="Models\Rdbms\LockDto.cs" />
|
||||
<Compile Include="ObjectResolution\ContainerLazyManyObjectsResolver.cs" />
|
||||
<Compile Include="ObjectResolution\ContainerManyObjectsResolver.cs" />
|
||||
<Compile Include="Models\Identity\IdentityModelMappings.cs" />
|
||||
@@ -378,10 +379,13 @@
|
||||
<Compile Include="Models\Rdbms\AccessDto.cs" />
|
||||
<Compile Include="ObjectResolution\ContainerSingleObjectResolver.cs" />
|
||||
<Compile Include="Persistence\Constants-DbProviderNames.cs" />
|
||||
<Compile Include="Persistence\Constants-Locks.cs" />
|
||||
<Compile Include="Persistence\FaultHandling\RetryDbConnection.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Persistence\IUmbracoDatabaseConfig.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionEight\AddLockObjects.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionEight\AddLockTable.cs" />
|
||||
<Compile Include="Persistence\UnitOfWorkExtensions.cs" />
|
||||
<Compile Include="Persistence\Mappers\AuditItemMapper.cs" />
|
||||
<Compile Include="Persistence\Mappers\IMappingResolver.cs" />
|
||||
@@ -471,7 +475,7 @@
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IMediaTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\INotificationsRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IAuditRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IContentTypeCompositionRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IContentTypeRepositoryBase.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IDomainRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IExternalLoginRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IMigrationEntryRepository.cs" />
|
||||
@@ -508,6 +512,7 @@
|
||||
<Compile Include="Security\EmailService.cs" />
|
||||
<Compile Include="SemVersionExtensions.cs" />
|
||||
<Compile Include="Serialization\NoTypeConverterJsonConverter.cs" />
|
||||
<Compile Include="ServiceContextExtensions.cs" />
|
||||
<Compile Include="ServiceProviderExtensions.cs" />
|
||||
<Compile Include="IO\ResizedImage.cs" />
|
||||
<Compile Include="IO\UmbracoMediaFile.cs" />
|
||||
@@ -524,14 +529,17 @@
|
||||
<Compile Include="Services\DomainService.cs" />
|
||||
<Compile Include="Services\ExternalLoginService.cs" />
|
||||
<Compile Include="Services\IAuditService.cs" />
|
||||
<Compile Include="Services\IContentTypeServiceBase.cs" />
|
||||
<Compile Include="Services\IDomainService.cs" />
|
||||
<Compile Include="Services\IExternalLoginService.cs" />
|
||||
<Compile Include="Services\IMediaTypeService.cs" />
|
||||
<Compile Include="Services\IMigrationEntryService.cs" />
|
||||
<Compile Include="Services\IPublicAccessService.cs" />
|
||||
<Compile Include="Services\IServerRegistrationService.cs" />
|
||||
<Compile Include="Services\ITaskService.cs" />
|
||||
<Compile Include="Services\LocalizedTextServiceSupplementaryFileSource.cs" />
|
||||
<Compile Include="Models\MediaExtensions.cs" />
|
||||
<Compile Include="Services\MediaTypeService.cs" />
|
||||
<Compile Include="Services\MigrationEntryService.cs" />
|
||||
<Compile Include="Services\MoveOperationStatusType.cs" />
|
||||
<Compile Include="Services\PublicAccessService.cs" />
|
||||
@@ -996,7 +1004,7 @@
|
||||
<Compile Include="Persistence\Querying\Query.cs" />
|
||||
<Compile Include="Persistence\Querying\SqlTranslator.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentTypeBaseRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentTypeRepositoryBase.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DataTypeDefinitionRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DictionaryRepository.cs" />
|
||||
@@ -1196,7 +1204,6 @@
|
||||
<Compile Include="PropertyEditors\ValueConverters\YesNoValueConverter.cs" />
|
||||
<Compile Include="Publishing\BasePublishingStrategy.cs" />
|
||||
<Compile Include="Publishing\IPublishingStrategy.cs" />
|
||||
<Compile Include="Publishing\PublishingStrategy.cs" />
|
||||
<Compile Include="Publishing\PublishStatus.cs" />
|
||||
<Compile Include="Publishing\PublishStatusType.cs" />
|
||||
<Compile Include="Dynamics\QueryableExtensions.cs" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
@@ -9,69 +10,167 @@ namespace Umbraco.Tests.Models
|
||||
[TestFixture]
|
||||
public class ContentExtensionsTests : BaseUmbracoConfigurationTest
|
||||
{
|
||||
#region RequiresSaving
|
||||
|
||||
// when Published...
|
||||
|
||||
[Test]
|
||||
public void Should_Persist_Values_When_Saving_After_Publishing_But_No_Data_Changed()
|
||||
public void RequireSaving_PublishedAndThatsAll_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
//no version will be created if no data is changed
|
||||
content.Properties.First().Value = "hello world";
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Not_Persist_Values_When_Saving_After_Publishing_But_No_Data_Changed()
|
||||
public void RequireSaving_PublishedAndSavingAndNothingChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
Assert.IsFalse(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Create_New_Version_When_Publishing()
|
||||
public void RequireSaving_PublishedAndSavingAndUserPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.Properties.First().Value = "hello world"; // change data
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireSaving_PublishedAndSavingAndContentPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ReleaseDate = DateTime.Now; // change data
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireSaving_PublishedAndUnpublishing_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublishing); // unpublishing
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireSaving_PublishedAndPublishingAndNothingChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing); // publishing
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
// when Unpublished...
|
||||
|
||||
[Test]
|
||||
public void RequireSaving_UnpublishedAndSavingAndNothingChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
Assert.IsTrue(content.ShouldCreateNewVersion());
|
||||
|
||||
Assert.IsFalse(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Create_New_Version_When_Saving_After_Publishing()
|
||||
public void RequireSaving_UnpublishedAndSavingAndUserPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
//no version will be created if no data is changed
|
||||
content.Properties.First().Value = "hello world";
|
||||
content.Properties.First().Value = "hello world"; // change data
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
Assert.IsTrue(content.ShouldCreateNewVersion());
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Create_New_Version_When_Language_Changed()
|
||||
public void RequireSaving_UnpublishedAndSavingAndContentPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ReleaseDate = DateTime.Now; // change data
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireSaving_UnpublishedAndPublishing_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing); // publishing
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireSaving_When_UnpublishedAndUnpublishingAndNothingChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublishing); // unpublishing
|
||||
|
||||
Assert.IsTrue(content.RequiresSaving());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RequiresNewVersion
|
||||
|
||||
// when language...
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_LanguageChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
@@ -79,99 +178,465 @@ namespace Umbraco.Tests.Models
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.Language = "en-AU";
|
||||
Assert.IsTrue(content.ShouldCreateNewVersion(PublishedState.Unpublished));
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
// when Published...
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndThatsAll_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Create_New_Version_When_Any_Property_Value_Changed_And_Its_Already_Published()
|
||||
public void RequireNewVersion_PublishedAndPublishingAndNothingChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndPublishdingAndUserPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.Properties.First().Value = "hello world"; // change data
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndPublishdingAndContentPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ReleaseDate = DateTime.Now; // change content property
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndSavingAndNothingChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndSavingAndUserPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.Properties.First().Value = "hello world"; // change data
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndSavingAndContentPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ReleaseDate = DateTime.Now; // change content property
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_PublishedAndUnpublishing_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublishing); // unpublishing
|
||||
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
// when Unpublished...
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_UnpublishedAndSavingAndNothingChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.Properties.First().Value = "hello world";
|
||||
Assert.IsTrue(content.ShouldCreateNewVersion(PublishedState.Published));
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test] // debatable
|
||||
public void RequireNewVersion_UnpublishedAndSavingAndUserPropertyChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.Properties.First().Value = "hello world"; // change user property
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_UnpublishedAndSavingAndContentPropertyChanged_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ReleaseDate = DateTime.Now; // change content property
|
||||
|
||||
Assert.IsTrue(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_UnpublishedAndPublishingAndNothingChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_UnpublishedAndPublishingAndUserPropertyChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.Properties.First().Value = "hello world"; // change user property
|
||||
content.ChangePublishedState(PublishedState.Publishing); // publishing
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_UnpublishedAndPublishingAndContentPropertyChanged_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ReleaseDate = DateTime.Now; // change content property
|
||||
content.ChangePublishedState(PublishedState.Publishing); // publishing
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequireNewVersion_UnpublishedAndUnpublishing_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublishing); // unpublishing
|
||||
|
||||
Assert.IsFalse(content.RequiresNewVersion());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ClearPublishedFlag
|
||||
|
||||
[Test]
|
||||
public void ClearPublishedFlag_UnpublishedAndPublishing_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
Assert.IsTrue(content.RequiresClearPublishedFlag());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearPublishedFlag_UnpublishedAndUnpublishing_Should()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublishing); // unpublishing - does not "change it"
|
||||
Assert.IsTrue(content.RequiresClearPublishedFlag());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearPublishedFlag_UnpublishedAndSaving_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
Assert.IsFalse(content.RequiresClearPublishedFlag());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearPublishedFlag_PublishedAndSaving_ShouldNot()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saving); // saving
|
||||
Assert.IsFalse(content.RequiresClearPublishedFlag());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearPublishedFlag_PublishedAndUnpublishing_Not()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublishing); // unpublishing
|
||||
Assert.IsTrue(content.RequiresClearPublishedFlag());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearPublishedFlag_When_PublishedAndPublishing_Not()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
content.ChangePublishedState(PublishedState.Publishing); // publishing - does not "change it"
|
||||
Assert.IsTrue(content.RequiresClearPublishedFlag());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Others
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_Reset_Clears_SavedPublishedState()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saving); // saved
|
||||
content.ResetDirtyProperties(false); // reset to .Unpublished
|
||||
Assert.AreEqual(PublishedState.Unpublished, content.PublishedState);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_OnlyIfActuallyChanged_Content()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
// if you assign a content property with its value it is not dirty
|
||||
// if you assign it with another value then back, it is dirty
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsPropertyDirty("Published"));
|
||||
content.Published = true;
|
||||
Assert.IsTrue(content.IsPropertyDirty("Published"));
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsPropertyDirty("Published"));
|
||||
content.Published = true;
|
||||
Assert.IsFalse(content.IsPropertyDirty("Published"));
|
||||
content.Published = false;
|
||||
content.Published = true;
|
||||
Assert.IsTrue(content.IsPropertyDirty("Published"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_OnlyIfActuallyChanged_User()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
var prop = content.Properties.First();
|
||||
|
||||
// if you assign a user property with its value it is not dirty
|
||||
// if you assign it with another value then back, it is dirty
|
||||
|
||||
prop.Value = "A";
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(prop.IsDirty());
|
||||
prop.Value = "B";
|
||||
Assert.IsTrue(prop.IsDirty());
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(prop.IsDirty());
|
||||
prop.Value = "B";
|
||||
Assert.IsFalse(prop.IsDirty());
|
||||
prop.Value = "A";
|
||||
prop.Value = "B";
|
||||
Assert.IsTrue(prop.IsDirty());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_UpdateDate()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
var prop = content.Properties.First();
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
var d = content.UpdateDate;
|
||||
prop.Value = "A";
|
||||
Assert.IsTrue(content.IsAnyUserPropertyDirty());
|
||||
Assert.IsFalse(content.IsEntityDirty());
|
||||
Assert.AreEqual(d, content.UpdateDate);
|
||||
|
||||
content.UpdateDate = DateTime.Now;
|
||||
Assert.IsTrue(content.IsEntityDirty());
|
||||
Assert.AreNotEqual(d, content.UpdateDate);
|
||||
|
||||
// so... changing UpdateDate would count as a content property being changed
|
||||
// however in ContentRepository.PersistUpdatedItem, we change UpdateDate AFTER
|
||||
// we've tested for RequiresSaving & RequiresNewVersion so it's OK
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_WasDirty_ContentProperty()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.Published = false;
|
||||
content.Published = true;
|
||||
Assert.IsTrue(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.Published = false;
|
||||
content.Published = true;
|
||||
content.ResetDirtyProperties(true); // what PersistUpdatedItem does
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsTrue(content.WasDirty());
|
||||
content.Published = false;
|
||||
content.Published = true;
|
||||
content.ResetDirtyProperties(); // what PersistUpdatedItem does
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsTrue(content.WasDirty());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_WasDirty_ContentSortOrder()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.SortOrder = 0;
|
||||
content.SortOrder = 1;
|
||||
Assert.IsTrue(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.SortOrder = 0;
|
||||
content.SortOrder = 1;
|
||||
content.ResetDirtyProperties(true); // what PersistUpdatedItem does
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsTrue(content.WasDirty());
|
||||
content.SortOrder = 0;
|
||||
content.SortOrder = 1;
|
||||
content.ResetDirtyProperties(); // what PersistUpdatedItem does
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsTrue(content.WasDirty());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DirtyProperty_WasDirty_UserProperty()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
var prop = content.Properties.First();
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
prop.Value = "a";
|
||||
prop.Value = "b";
|
||||
Assert.IsTrue(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
content.ResetDirtyProperties(false);
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
Assert.IsFalse(content.WasDirty());
|
||||
prop.Value = "a";
|
||||
prop.Value = "b";
|
||||
content.ResetDirtyProperties(true); // what PersistUpdatedItem does
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
//Assert.IsFalse(content.WasDirty()); // not impacted by user properties
|
||||
Assert.IsTrue(content.WasDirty()); // now it is!
|
||||
prop.Value = "a";
|
||||
prop.Value = "b";
|
||||
content.ResetDirtyProperties(); // what PersistUpdatedItem does
|
||||
Assert.IsFalse(content.IsDirty());
|
||||
//Assert.IsFalse(content.WasDirty()); // not impacted by user properties
|
||||
Assert.IsTrue(content.WasDirty()); // now it is!
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Not_Create_New_Version_When_Published_Status_Not_Changed()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
Assert.IsFalse(content.ShouldCreateNewVersion(PublishedState.Unpublished));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Not_Create_New_Version_When_Not_Published_And_Property_Changed()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.Properties.First().Value = "hello world";
|
||||
Assert.IsFalse(content.ShouldCreateNewVersion(PublishedState.Unpublished));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Clear_Published_Flag_When_Newly_Published_Version()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
Assert.IsTrue(content.ShouldClearPublishedFlagForPreviousVersions());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Not_Clear_Published_Flag_When_Saving_Version()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
Assert.IsFalse(content.ShouldClearPublishedFlagForPreviousVersions());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Clear_Published_Flag_When_Unpublishing_From_Published()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
Assert.IsTrue(content.ShouldClearPublishedFlagForPreviousVersions());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_Not_Clear_Published_Flag_When_Unpublishing_From_Saved()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
Assert.IsFalse(content.ShouldClearPublishedFlagForPreviousVersions());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Tests.Models
|
||||
[TearDown]
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
[TestCase("-1,-20,12,34,56", false)]
|
||||
@@ -41,10 +41,19 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
var mediaType = MockedContentTypes.CreateImageMediaType();
|
||||
var media = MockedMedia.CreateMediaFile(mediaType, -1);
|
||||
|
||||
// this is NOT how we should do it, we should "move to recycle bin"
|
||||
// as it causes various things to change... IsInRecycleBin looks for
|
||||
// the path but Trashed looks for the flag!
|
||||
// fixme .Trashed is weird anyways, should be refactored
|
||||
media.Path = path;
|
||||
((Media)media).Trashed = isInBin;
|
||||
|
||||
media.Id = 34;
|
||||
|
||||
Assert.AreEqual(isInBin, media.IsInRecycleBin());
|
||||
if (isInBin)
|
||||
Assert.IsTrue(media.Trashed);
|
||||
}
|
||||
|
||||
[TestCase("-1,-20,12,34,56", true)]
|
||||
@@ -54,10 +63,19 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType();
|
||||
var content = MockedContent.CreateSimpleContent(contentType);
|
||||
|
||||
// this is NOT how we should do it, we should "move to recycle bin"
|
||||
// as it causes various things to change... IsInRecycleBin looks for
|
||||
// the path but Trashed looks for the flag!
|
||||
// fixme .Trashed is weird anyways, should be refactored
|
||||
content.Path = path;
|
||||
content.Trashed = isInBin;
|
||||
|
||||
content.Id = 34;
|
||||
|
||||
Assert.AreEqual(isInBin, content.IsInRecycleBin());
|
||||
if (isInBin)
|
||||
Assert.IsTrue(content.Trashed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -67,7 +85,7 @@ namespace Umbraco.Tests.Models
|
||||
//add non-grouped properties
|
||||
contentType.AddPropertyType(new PropertyType("test", DataTypeDatabaseType.Ntext, "nonGrouped1") { Name = "Non Grouped 1", Description = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
|
||||
contentType.AddPropertyType(new PropertyType("test", DataTypeDatabaseType.Ntext, "nonGrouped2") { Name = "Non Grouped 2", Description = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
|
||||
|
||||
|
||||
//ensure that nothing is marked as dirty
|
||||
contentType.ResetDirtyProperties(false);
|
||||
|
||||
@@ -249,6 +267,13 @@ namespace Umbraco.Tests.Models
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
contentType.Id = 99;
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
// should not try to clone something that's not Published or Unpublished
|
||||
// (and in fact it will not work)
|
||||
// but we cannot directly set the state to Published - hence this trick
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.ResetDirtyProperties(false); // => .Published
|
||||
|
||||
var i = 200;
|
||||
foreach (var property in content.Properties)
|
||||
{
|
||||
@@ -263,7 +288,6 @@ namespace Umbraco.Tests.Models
|
||||
content.Level = 3;
|
||||
content.Path = "-1,4,10";
|
||||
content.ReleaseDate = DateTime.Now;
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.SortOrder = 5;
|
||||
content.Template = new Template((string) "Test Template", (string) "testTemplate")
|
||||
{
|
||||
@@ -366,7 +390,7 @@ namespace Umbraco.Tests.Models
|
||||
content.Level = 3;
|
||||
content.Path = "-1,4,10";
|
||||
content.ReleaseDate = DateTime.Now;
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
content.SortOrder = 5;
|
||||
content.Template = new Template((string) "Test Template", (string) "testTemplate")
|
||||
{
|
||||
@@ -642,7 +666,7 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
// Act
|
||||
content.ResetDirtyProperties();
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
|
||||
// Assert
|
||||
Assert.That(content.IsPropertyDirty("Published"), Is.True);
|
||||
@@ -650,23 +674,6 @@ namespace Umbraco.Tests.Models
|
||||
Assert.That(content.IsPropertyDirty("Name"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Verify_Content_Is_Trashed()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
|
||||
|
||||
// Act
|
||||
content.ResetDirtyProperties();
|
||||
content.ChangeTrashedState(true);
|
||||
|
||||
// Assert
|
||||
Assert.That(content.IsPropertyDirty("Trashed"), Is.True);
|
||||
Assert.That(content.Trashed, Is.True);
|
||||
Assert.That(content.IsPropertyDirty("Name"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Adding_PropertyGroup_To_ContentType_Results_In_Dirty_Entity()
|
||||
{
|
||||
@@ -689,7 +696,7 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
// Arrange
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
contentType.ResetDirtyProperties(); //reset
|
||||
contentType.ResetDirtyProperties(); //reset
|
||||
|
||||
// Act
|
||||
contentType.Alias = "newAlias";
|
||||
@@ -719,7 +726,7 @@ namespace Umbraco.Tests.Models
|
||||
Assert.That(content.GetDirtyUserProperties().Count(), Is.EqualTo(1));
|
||||
Assert.That(content.Properties[0].IsDirty(), Is.True);
|
||||
Assert.That(content.Properties["title"].IsDirty(), Is.True);
|
||||
|
||||
|
||||
content.ResetDirtyProperties(); //this would be like committing the entity
|
||||
|
||||
// Assert
|
||||
@@ -739,7 +746,7 @@ namespace Umbraco.Tests.Models
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
|
||||
// Act
|
||||
contentType.Alias = "newAlias";
|
||||
contentType.Alias = "newAlias";
|
||||
|
||||
// Assert
|
||||
Assert.That(contentType.IsDirty(), Is.True);
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MockedContentTypes.CreateImageMediaType("image2");
|
||||
ServiceContext.ContentTypeService.Save(mediaType);
|
||||
ServiceContext.MediaTypeService.Save(mediaType);
|
||||
|
||||
var media = MockedMedia.CreateMediaImage(mediaType, -1);
|
||||
ServiceContext.MediaService.Save(media, 0);
|
||||
|
||||
@@ -82,20 +82,20 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType1);
|
||||
c1.ChangePublishedState(PublishedState.Published);
|
||||
c1.ChangePublishedState(PublishedState.Publishing);
|
||||
repository.AddOrUpdate(c1);
|
||||
allCreated.Add(c1);
|
||||
}
|
||||
unitOfWork.Flush();
|
||||
|
||||
//now create some versions of this content - this shouldn't affect the xml structures saved
|
||||
for (int i = 0; i < allCreated.Count; i++)
|
||||
for (var i = 0; i < allCreated.Count; i++)
|
||||
{
|
||||
allCreated[i].Name = "blah" + i;
|
||||
//IMPORTANT testing note here: We need to changed the published state here so that
|
||||
// it doesn't automatically think this is simply publishing again - this forces the latest
|
||||
// version to be Saved and not published
|
||||
allCreated[i].ChangePublishedState(PublishedState.Saved);
|
||||
allCreated[i].ChangePublishedState(PublishedState.Saving);
|
||||
repository.AddOrUpdate(allCreated[i]);
|
||||
}
|
||||
unitOfWork.Flush();
|
||||
@@ -104,7 +104,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
unitOfWork.Database.Execute("DELETE FROM cmsContentXml");
|
||||
Assert.AreEqual(0, unitOfWork.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM cmsContentXml"));
|
||||
|
||||
repository.RebuildXmlStructures(media => new XElement("test"), 10);
|
||||
repository.RebuildXmlStructures(content => new XElement("test"), 10);
|
||||
|
||||
Assert.AreEqual(100, unitOfWork.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM cmsContentXml"));
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType1);
|
||||
c1.ChangePublishedState(PublishedState.Published);
|
||||
c1.ChangePublishedState(PublishedState.Publishing);
|
||||
repository.AddOrUpdate(c1);
|
||||
allCreated.Add(c1);
|
||||
}
|
||||
@@ -188,21 +188,21 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
for (var i = 0; i < 30; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType1);
|
||||
c1.ChangePublishedState(PublishedState.Published);
|
||||
c1.ChangePublishedState(PublishedState.Publishing);
|
||||
repository.AddOrUpdate(c1);
|
||||
allCreated.Add(c1);
|
||||
}
|
||||
for (var i = 0; i < 30; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType2);
|
||||
c1.ChangePublishedState(PublishedState.Published);
|
||||
c1.ChangePublishedState(PublishedState.Publishing);
|
||||
repository.AddOrUpdate(c1);
|
||||
allCreated.Add(c1);
|
||||
}
|
||||
for (var i = 0; i < 30; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType3);
|
||||
c1.ChangePublishedState(PublishedState.Published);
|
||||
c1.ChangePublishedState(PublishedState.Publishing);
|
||||
repository.AddOrUpdate(c1);
|
||||
allCreated.Add(c1);
|
||||
}
|
||||
@@ -536,13 +536,13 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var result = repository.GetAll().ToArray();
|
||||
foreach (var content in result)
|
||||
{
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
content.ChangePublishedState(PublishedState.Saving);
|
||||
repository.AddOrUpdate(content);
|
||||
}
|
||||
unitOfWork.Flush();
|
||||
foreach (var content in result)
|
||||
{
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ChangePublishedState(PublishedState.Publishing);
|
||||
repository.AddOrUpdate(content);
|
||||
}
|
||||
unitOfWork.Flush();
|
||||
|
||||
@@ -553,17 +553,17 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
public void CreateTestData()
|
||||
{
|
||||
//Create and Save folder-Media -> (NodeDto.NodeIdSeed)
|
||||
var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var folderMediaType = ServiceContext.MediaTypeService.Get(1031);
|
||||
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
|
||||
ServiceContext.MediaService.Save(folder, 0);
|
||||
|
||||
//Create and Save image-Media -> (NodeDto.NodeIdSeed + 1)
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
var imageMediaType = ServiceContext.MediaTypeService.Get(1032);
|
||||
var image = MockedMedia.CreateMediaImage(imageMediaType, folder.Id);
|
||||
ServiceContext.MediaService.Save(image, 0);
|
||||
|
||||
//Create and Save file-Media -> (NodeDto.NodeIdSeed + 2)
|
||||
var fileMediaType = ServiceContext.ContentTypeService.GetMediaType(1033);
|
||||
var fileMediaType = ServiceContext.MediaTypeService.Get(1033);
|
||||
var file = MockedMedia.CreateMediaFile(fileMediaType, folder.Id);
|
||||
ServiceContext.MediaService.Save(file, 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Persistence
|
||||
{
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
[TestFixture]
|
||||
public class UnitOfWorkTests : BaseDatabaseFactoryTest
|
||||
{
|
||||
[Test]
|
||||
public void ReadLockNonExisting()
|
||||
{
|
||||
var provider = new NPocoUnitOfWorkProvider(Logger);
|
||||
Assert.Throws<Exception>(() =>
|
||||
{
|
||||
using (var uow = provider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(-666);
|
||||
uow.Complete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadLockExisting()
|
||||
{
|
||||
var provider = new NPocoUnitOfWorkProvider(Logger);
|
||||
using (var uow = provider.CreateUnitOfWork())
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.Servers);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteLockNonExisting()
|
||||
{
|
||||
var provider = new NPocoUnitOfWorkProvider(Logger);
|
||||
Assert.Throws<Exception>(() =>
|
||||
{
|
||||
using (var uow = provider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(-666);
|
||||
uow.Complete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteLockExisting()
|
||||
{
|
||||
var provider = new NPocoUnitOfWorkProvider(Logger);
|
||||
using (var uow = provider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(Constants.Locks.Servers);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
Name = "Rich Text",
|
||||
DataTypeDefinitionId = -87 //tiny mce
|
||||
});
|
||||
ServiceContext.ContentTypeService.Save(mType);
|
||||
ServiceContext.MediaTypeService.Save(mType);
|
||||
var media = MockedMedia.CreateMediaImage(mType, -1);
|
||||
media.Properties["content"].Value = "<div>This is some content</div>";
|
||||
ServiceContext.MediaService.Save(media);
|
||||
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Publishing;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
@@ -28,7 +29,7 @@ namespace Umbraco.Tests.Publishing
|
||||
base.TearDown();
|
||||
|
||||
//ensure event handler is gone
|
||||
PublishingStrategy.Publishing -= PublishingStrategyPublishing;
|
||||
ContentService.Publishing -= StrategyPublishing;
|
||||
}
|
||||
|
||||
private IContent _homePage;
|
||||
@@ -49,18 +50,17 @@ namespace Umbraco.Tests.Publishing
|
||||
var testData = CreateTestData();
|
||||
//Create some other data which are descendants of Text Page 2
|
||||
var mandatorContent = MockedContent.CreateSimpleContent(
|
||||
ServiceContext.ContentTypeService.GetContentType("umbMandatory"), "Invalid Content", testData.Single(x => x.Name == "Text Page 2").Id);
|
||||
ServiceContext.ContentTypeService.Get("umbMandatory"), "Invalid Content", testData.Single(x => x.Name == "Text Page 2").Id);
|
||||
mandatorContent.SetValue("author", string.Empty);
|
||||
ServiceContext.ContentService.Save(mandatorContent, 0);
|
||||
var subContent = MockedContent.CreateSimpleContent(
|
||||
ServiceContext.ContentTypeService.GetContentType("umbTextpage"), "Sub Sub Sub", mandatorContent.Id);
|
||||
ServiceContext.ContentTypeService.Get("umbTextpage"), "Sub Sub Sub", mandatorContent.Id);
|
||||
ServiceContext.ContentService.Save(subContent, 0);
|
||||
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var listToPublish = ServiceContext.ContentService.GetDescendants(_homePage.Id).Concat(new[] { _homePage });
|
||||
var result = strategy.PublishWithChildrenInternal(listToPublish, 0, true);
|
||||
var evtMsgs = new EventMessages();
|
||||
var result = ((ContentService)ServiceContext.ContentService).StrategyPublishWithChildren(listToPublish, null, 0, evtMsgs, true);
|
||||
|
||||
Assert.AreEqual(listToPublish.Count() - 2, result.Count(x => x.Success));
|
||||
Assert.IsTrue(result.Where(x => x.Success).Select(x => x.Result.ContentItem.Id)
|
||||
@@ -83,26 +83,22 @@ namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
CreateTestData();
|
||||
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
|
||||
|
||||
PublishingStrategy.Publishing +=PublishingStrategyPublishing;
|
||||
ContentService.Publishing += StrategyPublishing;
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var listToPublish = ServiceContext.ContentService.GetDescendants(_homePage.Id).Concat(new[] {_homePage});
|
||||
var result = strategy.PublishWithChildrenInternal(listToPublish, 0);
|
||||
var evtMsgs = new EventMessages();
|
||||
var result = ((ContentService)ServiceContext.ContentService).StrategyPublishWithChildren(listToPublish, null, 0, evtMsgs);
|
||||
|
||||
Assert.AreEqual(listToPublish.Count() - 2, result.Count(x => x.Success));
|
||||
Assert.IsTrue(result.Where(x => x.Success).Select(x => x.Result.ContentItem.Id)
|
||||
.ContainsAll(listToPublish.Where(x => x.Name != "Text Page 2" && x.Name != "Text Page 3").Select(x => x.Id)));
|
||||
}
|
||||
|
||||
static void PublishingStrategyPublishing(IPublishingStrategy sender, PublishEventArgs<IContent> e)
|
||||
static void StrategyPublishing(IContentService sender, PublishEventArgs<IContent> e)
|
||||
{
|
||||
foreach (var i in e.PublishedEntities.Where(i => i.Name == "Text Page 2"))
|
||||
{
|
||||
if (e.PublishedEntities.Any(x => x.Name == "Text Page 2"))
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -110,26 +106,27 @@ namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
CreateTestData();
|
||||
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
var evtMsgs = new EventMessages();
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var result1 = strategy.Publish(_homePage, 0);
|
||||
var result1 = ((ContentService)ServiceContext.ContentService).StrategyPublish(_homePage, false, 0, evtMsgs);
|
||||
Assert.IsTrue(result1);
|
||||
Assert.IsTrue(_homePage.Published);
|
||||
foreach (var c in ServiceContext.ContentService.GetChildren(_homePage.Id))
|
||||
{
|
||||
var r = strategy.Publish(c, 0);
|
||||
var r = ((ContentService)ServiceContext.ContentService).StrategyPublish(c, false, 0, evtMsgs);
|
||||
Assert.IsTrue(r);
|
||||
Assert.IsTrue(c.Published);
|
||||
}
|
||||
|
||||
//ok, all are published except the deepest descendant, we will pass in a flag to not include it to
|
||||
//be published
|
||||
var result = strategy.PublishWithChildrenInternal(
|
||||
ServiceContext.ContentService.GetDescendants(_homePage).Concat(new[] {_homePage}), 0, false);
|
||||
//be published - beware that StrategyPublishWithChildren expects content to be ordered by level
|
||||
var content = new[] {_homePage}.Union(ServiceContext.ContentService.GetDescendants(_homePage));
|
||||
var result = ((ContentService)ServiceContext.ContentService).StrategyPublishWithChildren(content, null, 0, evtMsgs, false);
|
||||
//all of them will be SuccessAlreadyPublished unless the unpublished one gets included, in that case
|
||||
//we'll have a 'Success' result which we don't want.
|
||||
Assert.AreEqual(0, result.Count(x => x.Result.StatusType == PublishStatusType.Success));
|
||||
// NOTE - not true, we'll have Success for _homePage because we DO want to publish it
|
||||
Assert.AreEqual(1, result.Count(x => x.Result.StatusType == PublishStatusType.Success));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -137,17 +134,17 @@ namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
CreateTestData();
|
||||
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
var evtMsgs = new EventMessages();
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var result1 = strategy.Publish(_homePage, 0);
|
||||
var result1 = ((ContentService)ServiceContext.ContentService).StrategyPublish(_homePage, false, 0, evtMsgs);
|
||||
Assert.IsTrue(result1);
|
||||
Assert.IsTrue(_homePage.Published);
|
||||
|
||||
//NOTE (MCH) This isn't persisted, so not really a good test as it will look like the result should be something else.
|
||||
foreach (var c in ServiceContext.ContentService.GetChildren(_homePage.Id))
|
||||
{
|
||||
var r = strategy.Publish(c, 0);
|
||||
var r = ((ContentService)ServiceContext.ContentService).StrategyPublish(c, false, 0, evtMsgs);
|
||||
Assert.IsTrue(r);
|
||||
Assert.IsTrue(c.Published);
|
||||
}
|
||||
@@ -158,12 +155,16 @@ namespace Umbraco.Tests.Publishing
|
||||
//means the result will be 1 'SuccessAlreadyPublished' and 3 'Success' because the Homepage is
|
||||
//inserted in the list and since that item has the status of already being Published it will be the one item
|
||||
//with 'SuccessAlreadyPublished'
|
||||
//
|
||||
// NOTE - this is WRONG, the first one (_homepage) we really want to publish!
|
||||
// not sure this test makes sense at all...
|
||||
|
||||
var descendants = ServiceContext.ContentService.GetDescendants(_homePage).Concat(new[] {_homePage});
|
||||
var result = strategy.PublishWithChildrenInternal(descendants, 0, true);
|
||||
var contents = new[] {_homePage} // top-level MUST be the first one here
|
||||
.Concat(ServiceContext.ContentService.GetDescendants(_homePage));
|
||||
var result = ((ContentService)ServiceContext.ContentService).StrategyPublishWithChildren(contents, null, 0, evtMsgs, true);
|
||||
|
||||
Assert.AreEqual(3, result.Count(x => x.Result.StatusType == PublishStatusType.Success));
|
||||
Assert.AreEqual(1, result.Count(x => x.Result.StatusType == PublishStatusType.SuccessAlreadyPublished));
|
||||
Assert.AreEqual(4, result.Count(x => x.Result.StatusType == PublishStatusType.Success));
|
||||
Assert.AreEqual(0, result.Count(x => x.Result.StatusType == PublishStatusType.SuccessAlreadyPublished));
|
||||
Assert.IsTrue(result.First(x => x.Result.StatusType == PublishStatusType.Success).Success);
|
||||
Assert.IsTrue(result.First(x => x.Result.StatusType == PublishStatusType.Success).Result.ContentItem.Published);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Services
|
||||
//Create and Save Content "Text Page 1" based on "umbTextpage" -> 1047
|
||||
Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", textpage.Id);
|
||||
subpage.ReleaseDate = DateTime.Now.AddMinutes(-5);
|
||||
subpage.ChangePublishedState(PublishedState.Saved);
|
||||
subpage.ChangePublishedState(PublishedState.Saving);
|
||||
ServiceContext.ContentService.Save(subpage, 0);
|
||||
|
||||
//Create and Save Content "Text Page 1" based on "umbTextpage" -> 1048
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user