Merge with 6.0.0

This commit is contained in:
Shannon Deminick
2013-01-23 18:50:44 +03:00
294 changed files with 15704 additions and 3144 deletions

View File

@@ -39,6 +39,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\SQLCE4Umbraco.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

View File

@@ -1,11 +1,11 @@
using System;
using System;
using System.Reflection;
namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version(6, 0, 0);
private static readonly Version Version = new Version("6.0.0");
/// <summary>
/// Gets the current version of Umbraco.
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return ""; } }
public static string CurrentComment { get { return "RC"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx

View File

@@ -7,10 +7,13 @@ using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
namespace Umbraco.Core
{
@@ -40,7 +43,7 @@ namespace Umbraco.Core
//create database and service contexts for the app context
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName);
UmbracoDatabase.Mapper = new PetaPocoMapper();
Database.Mapper = new PetaPocoMapper();
var dbContext = new DatabaseContext(dbFactory);
var serviceContext = new ServiceContext(
new PetaPocoUnitOfWorkProvider(dbFactory),
@@ -132,12 +135,33 @@ namespace Umbraco.Core
MacroPropertyTypeResolver.Current = new MacroPropertyTypeResolver(
PluginManager.Current.ResolveMacroPropertyTypes());
//TODO: Y U NO WORK?
//MigrationResolver.Current = new MigrationResolver(
// PluginManager.Current.ResolveMigrationTypes());
//the database migration objects
MigrationResolver.Current = new MigrationResolver(new List<Type>
{
typeof (MigrationsVersionFourNineZero.RemoveUmbracoAppConstraints),
typeof (DeleteAppTables),
typeof (EnsureAppsTreesUpdated),
typeof (MoveMasterContentTypeData),
typeof (NewCmsContentType2ContentTypeTable),
typeof (RemoveMasterContentTypeColumn),
typeof (RenameCmsTabTable),
typeof (RenameTabIdColumn),
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
typeof (UpdateCmsContentTypeTable),
typeof (UpdateCmsContentVersionTable),
typeof (UpdateCmsPropertyTypeGroupTable)
});
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
PluginManager.Current.ResolvePropertyEditorValueConverters());
//add the internal ones, these are not public currently so need to add them manually
PropertyEditorValueConvertersResolver.Current.AddType<DatePickerPropertyEditorValueConverter>();
PropertyEditorValueConvertersResolver.Current.AddType<TinyMcePropertyEditorValueConverter>();
PropertyEditorValueConvertersResolver.Current.AddType<YesNoPropertyEditorValueConverter>();
}
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web;
namespace Umbraco.Core
{
@@ -158,7 +159,7 @@ namespace Umbraco.Core
var builder = new StringBuilder();
foreach (var i in d)
{
builder.Append(String.Format("{0}={1}&", i.Key, i.Value));
builder.Append(String.Format("{0}={1}&", HttpUtility.UrlEncode(i.Key), i.Value == null ? string.Empty : HttpUtility.UrlEncode(i.Value.ToString())));
}
return builder.ToString().TrimEnd('&');
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Dynamic;
using System.Reflection;
@@ -11,7 +12,8 @@ using System.Web;
namespace Umbraco.Core.Dynamics
{
public class DynamicXml : DynamicObject, IEnumerable<DynamicXml>, IEnumerable<XElement>
[TypeConverter(typeof(DynamicXmlConverter))]
public class DynamicXml : DynamicObject, IEnumerable<DynamicXml>, IEnumerable<XElement>
{
public XElement BaseElement { get; set; }
@@ -213,6 +215,16 @@ namespace Umbraco.Core.Dynamics
}
return root;
}
/// <summary>
/// Return the string version of Xml
/// </summary>
/// <returns></returns>
public override string ToString()
{
return ToXml();
}
public IHtmlString ToHtml()
{
return new HtmlString(this.ToXml());

View File

@@ -0,0 +1,59 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace Umbraco.Core.Dynamics
{
/// <summary>
/// A custom type converter for DynamicXml
/// </summary>
public class DynamicXmlConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
{
var convertableTypes = new[] {typeof(string), typeof(XElement), typeof(XmlElement), typeof(XmlDocument)};
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType))
|| base.CanConvertFrom(context, sourceType);
}
public override object ConvertTo(
ITypeDescriptorContext context,
CultureInfo culture,
object value,
Type destinationType)
{
var dxml = value as DynamicXml;
if (dxml == null)
return null;
//string
if (TypeHelper.IsTypeAssignableFrom<string>(destinationType))
{
return value.ToString();
}
//XElement
if (TypeHelper.IsTypeAssignableFrom<XElement>(destinationType))
{
return dxml.BaseElement;
}
//XmlElement
if (TypeHelper.IsTypeAssignableFrom<XmlElement>(destinationType))
{
var xDoc = new XmlDocument();
xDoc.LoadXml(dxml.ToString());
return xDoc.DocumentElement;
}
//XmlDocument
if (TypeHelper.IsTypeAssignableFrom<XmlDocument>(destinationType))
{
var xDoc = new XmlDocument();
xDoc.LoadXml(dxml.ToString());
return xDoc;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Persistence.Migrations;
namespace Umbraco.Core.Events
{
public class MigrationEventArgs : CancellableObjectEventArgs<IEnumerable<IMigration>>
{
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
/// </summary>
/// <param name="eventObject"></param>
/// <param name="targetVersion"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
public MigrationEventArgs(IEnumerable<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
ConfiguredVersion = configuredVersion;
TargetVersion = targetVersion;
}
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
/// </summary>
/// <param name="eventObject"></param>
/// <param name="migrationContext"></param>
/// <param name="targetVersion"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
internal MigrationEventArgs(IEnumerable<IMigration> eventObject, MigrationContext migrationContext, Version configuredVersion, Version targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
MigrationContext = migrationContext;
ConfiguredVersion = configuredVersion;
TargetVersion = targetVersion;
}
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
/// </summary>
/// <param name="eventObject"></param>
/// <param name="configuredVersion"></param>
/// <param name="targetVersion"></param>
public MigrationEventArgs(IEnumerable<IMigration> eventObject, Version configuredVersion, Version targetVersion)
: base(eventObject)
{
ConfiguredVersion = configuredVersion;
TargetVersion = targetVersion;
}
/// <summary>
/// Returns all migrations that were used in the migration runner
/// </summary>
public IEnumerable<IMigration> Migrations
{
get { return EventObject; }
}
public Version ConfiguredVersion { get; private set; }
public Version TargetVersion { get; private set; }
internal MigrationContext MigrationContext { get; private set; }
}
}

View File

@@ -1,11 +1,12 @@
using Umbraco.Core.CodeAnnotations;
using System.IO;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.IO
{
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
public static class FileSystemExtensions
{
[UmbracoExperimentalFeature("", "Will be declared public after 4.10")]
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal static long GetSize(this IFileSystem fs, string path)
{
var s = fs.OpenFile(path);
@@ -15,10 +16,22 @@ namespace Umbraco.Core.IO
return size;
}
[UmbracoExperimentalFeature("", "Will be declared public after 4.10")]
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal static void CopyFile(this IFileSystem fs, string path, string newPath)
{
fs.AddFile(newPath, fs.OpenFile(path));
}
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal static string GetExtension(this IFileSystem fs, string path)
{
return Path.GetExtension(fs.GetFullPath(path));
}
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal static string GetFileName(this IFileSystem fs, string path)
{
return Path.GetFileName(fs.GetFullPath(path));
}
}
}

View File

@@ -15,8 +15,7 @@ namespace Umbraco.Core.IO
///
/// This abstract class just wraps the 'real' IFileSystem object passed in to its constructor.
/// </remarks>
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal abstract class FileSystemWrapper : IFileSystem
public abstract class FileSystemWrapper : IFileSystem
{
private readonly IFileSystem _wrapped;

View File

@@ -5,8 +5,7 @@ using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.IO
{
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal interface IFileSystem
public interface IFileSystem
{
IEnumerable<string> GetDirectories(string path);

View File

@@ -11,8 +11,7 @@ namespace Umbraco.Core.IO
/// A custom file system provider for media
/// </summary>
[FileSystemProvider("media")]
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal class MediaFileSystem : FileSystemWrapper
public class MediaFileSystem : FileSystemWrapper
{
public MediaFileSystem(IFileSystem wrapped)
: base(wrapped)

View File

@@ -10,16 +10,19 @@ using Umbraco.Core.Publishing;
namespace Umbraco.Core.IO
{
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
internal class PhysicalFileSystem : IFileSystem
public class PhysicalFileSystem : IFileSystem
{
private readonly string _rootPath;
internal string RootPath { get; private set; }
private readonly string _rootUrl;
public PhysicalFileSystem(string virtualRoot)
{
_rootPath = System.Web.Hosting.HostingEnvironment.MapPath(virtualRoot);
_rootUrl = VirtualPathUtility.ToAbsolute(virtualRoot);
if (virtualRoot == null) throw new ArgumentNullException("virtualRoot");
if (!virtualRoot.StartsWith("~/"))
throw new ArgumentException("The virtualRoot argument must be a virtual path and start with '~/'");
RootPath = IOHelper.MapPath(virtualRoot);
_rootUrl = IOHelper.ResolveUrl(virtualRoot);
}
public PhysicalFileSystem(string rootPath, string rootUrl)
@@ -30,7 +33,10 @@ namespace Umbraco.Core.IO
if (string.IsNullOrEmpty(rootUrl))
throw new ArgumentException("The argument 'rootUrl' cannot be null or empty.");
_rootPath = rootPath;
if (rootPath.StartsWith("~/"))
throw new ArgumentException("The rootPath argument cannot be a virtual path and cannot start with '~/'");
RootPath = rootPath;
_rootUrl = rootUrl;
}
@@ -141,7 +147,7 @@ namespace Umbraco.Core.IO
}
catch (FileNotFoundException ex)
{
LogHelper.Info<PublishingStrategy>(string.Format("DeleteFile failed with FileNotFoundException: {0}", ex.InnerException));
LogHelper.Info<PhysicalFileSystem>(string.Format("DeleteFile failed with FileNotFoundException: {0}", ex.InnerException));
}
}
@@ -150,17 +156,12 @@ namespace Umbraco.Core.IO
return File.Exists(GetFullPath(path));
}
public string GetExtension(string path)
{
return Path.GetExtension(GetFullPath(path));
}
public string GetRelativePath(string fullPathOrUrl)
{
var relativePath = fullPathOrUrl
.TrimStart(_rootUrl)
.Replace('/', Path.DirectorySeparatorChar)
.TrimStart(_rootPath)
.TrimStart(RootPath)
.TrimStart(Path.DirectorySeparatorChar);
return relativePath;
@@ -168,8 +169,8 @@ namespace Umbraco.Core.IO
public string GetFullPath(string path)
{
return !path.StartsWith(_rootPath)
? Path.Combine(_rootPath, path)
return !path.StartsWith(RootPath)
? Path.Combine(RootPath, path)
: path;
}

View File

@@ -19,25 +19,28 @@ namespace Umbraco.Core.Models
private DateTime? _releaseDate;
private DateTime? _expireDate;
private int _writer;
private string _nodeName;
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
/// <summary>
/// Constructor for creating a Content object
/// </summary>
/// <param name="parentId">Id of the Parent content</param>
/// <param name="name">Name of the content</param>
/// <param name="parent">Parent <see cref="IContent"/> object</param>
/// <param name="contentType">ContentType for the current Content object</param>
public Content(int parentId, IContentType contentType)
: this(parentId, contentType, new PropertyCollection())
{
}
public Content(IContent parent, IContentType contentType)
: this(parent, contentType, new PropertyCollection())
public Content(string name, IContent parent, IContentType contentType)
: this(name, parent, contentType, new PropertyCollection())
{
}
public Content(IContent parent, IContentType contentType, PropertyCollection properties)
: base(parent, contentType, properties)
/// <summary>
/// Constructor for creating a Content object
/// </summary>
/// <param name="name">Name of the content</param>
/// <param name="parent">Parent <see cref="IContent"/> object</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="properties">Collection of properties</param>
public Content(string name, IContent parent, IContentType contentType, PropertyCollection properties)
: base(name, parent, contentType, properties)
{
Mandate.ParameterNotNull(contentType, "contentType");
@@ -47,11 +50,23 @@ namespace Umbraco.Core.Models
/// <summary>
/// Constructor for creating a Content object
/// </summary>
/// <param name="name">Name of the content</param>
/// <param name="parentId">Id of the Parent content</param>
/// <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
/// </summary>
/// <param name="name">Name of the content</param>
/// <param name="parentId">Id of the Parent content</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="properties">Collection of properties</param>
public Content(int parentId, IContentType contentType, PropertyCollection properties)
: base(parentId, contentType, properties)
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
: base(name, parentId, contentType, properties)
{
Mandate.ParameterNotNull(contentType, "contentType");
@@ -189,6 +204,12 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Name of the Node (non-localized).
/// </summary>
/// <remarks>
/// This Property is kept internal until localization is introduced.
/// </remarks>
internal string NodeName
{
get { return _nodeName; }
@@ -246,20 +267,20 @@ namespace Umbraco.Core.Models
/// <summary>
/// Changes the Published state of the content object
/// </summary>
/// <param name="isPublished">Boolean indicating whether content is published (true) or unpublished (false)</param>
public void ChangePublishedState(bool isPublished)
public void ChangePublishedState(PublishedState state)
{
Published = isPublished;
//NOTE Should this be checked against the Expire/Release dates?
//TODO possibly create new (unpublished version)?
Published = state == PublishedState.Published;
PublishedState = state;
}
internal PublishedState PublishedState { get; set; }
/// <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 void ChangeTrashedState(bool isTrashed, int parentId = -1)
public override void ChangeTrashedState(bool isTrashed, int parentId = -1)
{
Trashed = isTrashed;
@@ -276,7 +297,7 @@ namespace Umbraco.Core.Models
//If the content is trashed and is published it should be marked as unpublished
if (isTrashed && Published)
{
ChangePublishedState(false);
ChangePublishedState(PublishedState.Unpublished);
}
}

View File

@@ -5,6 +5,7 @@ using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Web;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
@@ -16,7 +17,7 @@ namespace Umbraco.Core.Models
{
protected IContentTypeComposition ContentTypeBase;
private Lazy<int> _parentId;
private string _name;
private string _name;//NOTE Once localization is introduced this will be the localized Name of the Content/Media.
private int _sortOrder;
private int _level;
private string _path;
@@ -25,34 +26,50 @@ namespace Umbraco.Core.Models
private int _contentTypeId;
private PropertyCollection _properties;
protected ContentBase(int parentId, IContentTypeComposition contentType, PropertyCollection properties)
/// <summary>
/// Protected constructor for ContentBase (Base for Content and Media)
/// </summary>
/// <param name="name">Localized Name of the entity</param>
/// <param name="parentId"></param>
/// <param name="contentType"></param>
/// <param name="properties"></param>
protected ContentBase(string name, int parentId, IContentTypeComposition contentType, PropertyCollection properties)
{
Mandate.ParameterCondition(parentId != 0, "parentId");
Mandate.ParameterNotNull(contentType, "contentType");
Mandate.ParameterNotNull(properties, "properties");
_parentId = new Lazy<int>(() => parentId);
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
ContentTypeBase = contentType;
Version = Guid.NewGuid();
_parentId = new Lazy<int>(() => parentId);
_name = name;
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
_properties = properties;
_properties.EnsurePropertyTypes(PropertyTypes);
Version = Guid.NewGuid();
}
protected ContentBase(IContentBase parent, IContentTypeComposition contentType, PropertyCollection properties)
/// <summary>
/// Protected constructor for ContentBase (Base for Content and Media)
/// </summary>
/// <param name="name">Localized Name of the entity</param>
/// <param name="parent"></param>
/// <param name="contentType"></param>
/// <param name="properties"></param>
protected ContentBase(string name, IContentBase parent, IContentTypeComposition contentType, PropertyCollection properties)
{
Mandate.ParameterNotNull(parent, "parent");
Mandate.ParameterNotNull(contentType, "contentType");
Mandate.ParameterNotNull(properties, "properties");
_parentId = new Lazy<int>(() => parent.Id);
ContentTypeBase = contentType;
Version = Guid.NewGuid();
_parentId = new Lazy<int>(() => parent.Id);
_name = name;
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
ContentTypeBase = contentType;
_properties = properties;
_properties.EnsurePropertyTypes(PropertyTypes);
Version = Guid.NewGuid();
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentBase, string>(x => x.Name);
@@ -256,11 +273,110 @@ namespace Umbraco.Core.Models
}
/// <summary>
/// Sets the value of a Property
/// Sets the <see cref="System.Object"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetValue(string propertyTypeAlias, object value)
{
if (value == null)
{
SetValueOnProperty(propertyTypeAlias, value);
return;
}
// .NET magic to call one of the 'SetPropertyValue' handlers with matching signature
((dynamic)this).SetPropertyValue(propertyTypeAlias, (dynamic)value);
}
/// <summary>
/// Sets the <see cref="System.String"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, string value)
{
SetValueOnProperty(propertyTypeAlias, value);
}
/// <summary>
/// Sets the <see cref="System.Int32"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, int value)
{
SetValueOnProperty(propertyTypeAlias, value);
}
/// <summary>
/// Sets the <see cref="System.Int64"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, long value)
{
string val = value.ToString();
SetValueOnProperty(propertyTypeAlias, val);
}
/// <summary>
/// Sets the <see cref="System.Boolean"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, bool value)
{
int val = Convert.ToInt32(value);
SetValueOnProperty(propertyTypeAlias, val);
}
/// <summary>
/// Sets the <see cref="System.DateTime"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, DateTime value)
{
SetValueOnProperty(propertyTypeAlias, value);
}
/// <summary>
/// Sets the <see cref="System.Web.HttpPostedFile"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, HttpPostedFile value)
{
ContentExtensions.SetValue(this, propertyTypeAlias, value);
}
/// <summary>
/// Sets the <see cref="System.Web.HttpPostedFileBase"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, HttpPostedFileBase value)
{
ContentExtensions.SetValue(this, propertyTypeAlias, value);
}
/// <summary>
/// Sets the <see cref="System.Web.HttpPostedFileWrapper"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
public virtual void SetPropertyValue(string propertyTypeAlias, HttpPostedFileWrapper value)
{
ContentExtensions.SetValue(this, propertyTypeAlias, value);
}
/// <summary>
/// Private method to set the value of a property
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
private void SetValueOnProperty(string propertyTypeAlias, object value)
{
if (Properties.Contains(propertyTypeAlias))
{
@@ -284,5 +400,7 @@ namespace Umbraco.Core.Models
{
return Properties.Any(property => !property.IsValid()) == false;
}
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -1);
}
}

View File

@@ -2,6 +2,7 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
@@ -53,13 +54,14 @@ namespace Umbraco.Core.Models
}
}
/*
/// <summary>
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
/// </summary>
/// <param name="media"><see cref="IMedia"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
public static void SetValue(this IMedia media, string propertyTypeAlias, HttpPostedFileBase value)
public static void SetPropertyValue(this IMedia media, string propertyTypeAlias, HttpPostedFileBase value)
{
var name =
IOHelper.SafeFileName(
@@ -77,7 +79,7 @@ namespace Umbraco.Core.Models
/// <param name="media"><see cref="IMedia"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFile"/> containing the file that will be uploaded</param>
public static void SetValue(this IMedia media, string propertyTypeAlias, HttpPostedFile value)
public static void SetPropertyValue(this IMedia media, string propertyTypeAlias, HttpPostedFile value)
{
var name =
IOHelper.SafeFileName(
@@ -95,19 +97,19 @@ namespace Umbraco.Core.Models
/// <param name="media"><see cref="IMedia"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFileWrapper"/> containing the file that will be uploaded</param>
public static void SetValue(this IMedia media, string propertyTypeAlias, HttpPostedFileWrapper value)
public static void SetPropertyValue(this IMedia media, string propertyTypeAlias, HttpPostedFileWrapper value)
{
if (string.IsNullOrEmpty(value.FileName) == false)
SetFileOnContent(media, propertyTypeAlias, value.FileName, value.InputStream);
}
*/
/// <summary>
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
/// </summary>
/// <param name="content"><see cref="IContent"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
public static void SetValue(this IContent content, string propertyTypeAlias, HttpPostedFileBase value)
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value)
{
var name =
IOHelper.SafeFileName(
@@ -125,7 +127,7 @@ namespace Umbraco.Core.Models
/// <param name="content"><see cref="IContent"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFile"/> containing the file that will be uploaded</param>
public static void SetValue(this IContent content, string propertyTypeAlias, HttpPostedFile value)
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFile value)
{
var name =
IOHelper.SafeFileName(
@@ -143,7 +145,7 @@ namespace Umbraco.Core.Models
/// <param name="content"><see cref="IContent"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFileWrapper"/> containing the file that will be uploaded</param>
public static void SetValue(this IContent content, string propertyTypeAlias, HttpPostedFileWrapper value)
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileWrapper value)
{
if (string.IsNullOrEmpty(value.FileName) == false)
SetFileOnContent(content, propertyTypeAlias, value.FileName, value.InputStream);
@@ -174,10 +176,10 @@ namespace Umbraco.Core.Models
//Look up Prevalues for this upload datatype - if it is an upload datatype
var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
if (property.PropertyType.DataTypeControlId == uploadFieldId)
if (property.PropertyType.DataTypeId == uploadFieldId)
{
//Get Prevalues by the DataType's Id: property.PropertyType.DataTypeId
var values = ApplicationContext.Current.Services.DataTypeService.GetPreValuesByDataTypeId(property.PropertyType.DataTypeId);
var values = ApplicationContext.Current.Services.DataTypeService.GetPreValuesByDataTypeId(property.PropertyType.DataTypeDefinitionId);
var thumbnailSizes = values.FirstOrDefault();
//Additional thumbnails configured as prevalues on the DataType
if (thumbnailSizes != null)
@@ -208,8 +210,8 @@ namespace Umbraco.Core.Models
//Only add dimensions to web images
if (supportsResizing)
{
SetPropertyValue(content, uploadFieldConfigNode, "widthFieldAlias", GetDimensions(fs, fileName).Item1);
SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", GetDimensions(fs, fileName).Item2);
SetPropertyValue(content, uploadFieldConfigNode, "widthFieldAlias", GetDimensions(fs, fileName).Item1.ToString(CultureInfo.InvariantCulture));
SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", GetDimensions(fs, fileName).Item2.ToString(CultureInfo.InvariantCulture));
}
else
{
@@ -217,7 +219,7 @@ namespace Umbraco.Core.Models
SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", string.Empty);
}
SetPropertyValue(content, uploadFieldConfigNode, "lengthFieldAlias", fs.GetSize(fileName));
SetPropertyValue(content, uploadFieldConfigNode, "lengthFieldAlias", fs.GetSize(fileName).ToString(CultureInfo.InvariantCulture));
SetPropertyValue(content, uploadFieldConfigNode, "extensionFieldAlias", extension);
}
}
@@ -226,7 +228,7 @@ namespace Umbraco.Core.Models
property.Value = fs.GetUrl(fileName);
}
private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, object propertyValue)
private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, string propertyValue)
{
XmlNode propertyNode = uploadFieldConfigNode.SelectSingleNode(propertyAlias);
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false)
@@ -403,9 +405,7 @@ namespace Umbraco.Core.Models
{
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
//var nodeName = content.ContentType.Alias.ToUmbracoAlias(StringAliasCaseType.CamelCase, true);
var nodeName = content.ContentType.Alias;
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck();
var x = content.ToXml(nodeName);
x.Add(new XAttribute("nodeType", content.ContentType.Id));
x.Add(new XAttribute("creatorName", content.GetCreatorProfile().Name));
@@ -458,7 +458,8 @@ namespace Umbraco.Core.Models
new XAttribute("nodeName", contentBase.Name),
new XAttribute("urlName", niceUrl),//Format Url ?
new XAttribute("path", contentBase.Path),
new XAttribute("isDoc", ""));
new XAttribute("isDoc", ""),
UmbracoSettings.UseLegacyXmlSchema ? new XAttribute("nodeTypeAlias", content.ContentType.Alias) : null);
foreach (var property in contentBase.Properties)
{

View File

@@ -72,6 +72,12 @@ namespace Umbraco.Core.Models
/// <param name="template">Default <see cref="ITemplate"/></param>
public void SetDefaultTemplate(ITemplate template)
{
if (template == null)
{
DefaultTemplateId = 0;
return;
}
DefaultTemplateId = template.Id;
if(_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
{

View File

@@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
@@ -29,6 +30,7 @@ namespace Umbraco.Core.Models
private bool _isContainer;
private bool _trashed;
private PropertyGroupCollection _propertyGroups;
private PropertyTypeCollection _propertyTypes;
private IEnumerable<ContentTypeSort> _allowedContentTypes;
protected ContentTypeBase(int parentId)
@@ -38,6 +40,7 @@ namespace Umbraco.Core.Models
_parentId = new Lazy<int>(() => parentId);
_allowedContentTypes = new List<ContentTypeSort>();
_propertyGroups = new PropertyGroupCollection();
_propertyTypes = new PropertyTypeCollection();
}
protected ContentTypeBase(IContentTypeBase parent)
@@ -47,6 +50,7 @@ namespace Umbraco.Core.Models
_parentId = new Lazy<int>(() => parent.Id);
_allowedContentTypes = new List<ContentTypeSort>();
_propertyGroups = new PropertyGroupCollection();
_propertyTypes = new PropertyTypeCollection();
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Name);
@@ -64,12 +68,18 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.Trashed);
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
private static readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<PropertyType>>(x => x.PropertyTypes);
protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(PropertyGroupCollectionSelector);
}
protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(PropertyTypeCollectionSelector);
}
/// <summary>
/// Gets or sets the Id of the Parent entity
/// </summary>
@@ -144,7 +154,12 @@ namespace Umbraco.Core.Models
get { return _alias; }
set
{
_alias = value;
//Ensures a valid ContentType alias
//Would have liked to use .ToUmbracoAlias() but that would break casing upon saving older/upgraded ContentTypes
var result = Regex.Replace(value, @"[^a-zA-Z0-9\s\.-]+", "", RegexOptions.Compiled);
result = result.Replace(" ", "");
_alias = result;
OnPropertyChanged(AliasSelector);
}
}
@@ -301,7 +316,16 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
public virtual IEnumerable<PropertyType> PropertyTypes
{
get { return PropertyGroups.SelectMany(x => x.PropertyTypes); }
get
{
var types = _propertyTypes.Union(PropertyGroups.SelectMany(x => x.PropertyTypes));
return types;
}
internal set
{
_propertyTypes = new PropertyTypeCollection(value);
_propertyTypes.CollectionChanged += PropertyTypesChanged;
}
}
/// <summary>

View File

@@ -69,14 +69,6 @@ namespace Umbraco.Core.Models
/// <summary>
/// Changes the Published state of the content object
/// </summary>
/// <param name="isPublished">Boolean indicating whether content is published (true) or unpublished (false)</param>
void ChangePublishedState(bool isPublished);
/// <summary>
/// Changes the Trashed state of the content object
/// </summary>
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
/// <param name="parentId"> </param>
void ChangeTrashedState(bool isTrashed, int parentId = -1);
void ChangePublishedState(PublishedState state);
}
}

View File

@@ -66,7 +66,7 @@ namespace Umbraco.Core.Models
TPassType GetValue<TPassType>(string propertyTypeAlias);
/// <summary>
/// Sets the value of a Property
/// Sets the <see cref="System.Object"/> value of a Property
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <param name="value">Value to set for the Property</param>
@@ -77,5 +77,12 @@ 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 = -1);
}
}

View File

@@ -15,20 +15,23 @@ namespace Umbraco.Core.Models
/// <summary>
/// Constructor for creating a Media object
/// </summary>
/// <param name="parentId"> </param>
/// <param name="name">ame of the Media object</param>
/// <param name="parent">Parent <see cref="IMedia"/> object</param>
/// <param name="contentType">MediaType for the current Media object</param>
public Media(int parentId, IMediaType contentType)
: this(parentId, contentType, new PropertyCollection())
{
}
public Media(IMedia parent, IMediaType contentType)
: this(parent, contentType, new PropertyCollection())
public Media(string name, IMedia parent, IMediaType contentType)
: this(name, parent, contentType, new PropertyCollection())
{
}
public Media(IMedia parent, IMediaType contentType, PropertyCollection properties)
: base(parent, contentType, properties)
/// <summary>
/// Constructor for creating a Media object
/// </summary>
/// <param name="name">ame of the Media object</param>
/// <param name="parent">Parent <see cref="IMedia"/> object</param>
/// <param name="contentType">MediaType for the current Media object</param>
/// <param name="properties">Collection of properties</param>
public Media(string name, IMedia parent, IMediaType contentType, PropertyCollection properties)
: base(name, parent, contentType, properties)
{
Mandate.ParameterNotNull(contentType, "contentType");
_contentType = contentType;
@@ -37,10 +40,23 @@ namespace Umbraco.Core.Models
/// <summary>
/// Constructor for creating a Media object
/// </summary>
/// <param name="parentId"> </param>
/// <param name="name">ame of the Media object</param>
/// <param name="parentId">Id of the Parent IMedia</param>
/// <param name="contentType">MediaType for the current Media object</param>
public Media(string name, int parentId, IMediaType contentType)
: this(name, parentId, contentType, new PropertyCollection())
{
}
/// <summary>
/// Constructor for creating a Media object
/// </summary>
/// <param name="name">Name of the Media object</param>
/// <param name="parentId">Id of the Parent IMedia</param>
/// <param name="contentType">MediaType for the current Media object</param>
/// <param name="properties">Collection of properties</param>
public Media(int parentId, IMediaType contentType, PropertyCollection properties) : base(parentId, contentType, properties)
public Media(string name, int parentId, IMediaType contentType, PropertyCollection properties)
: base(name, parentId, contentType, properties)
{
Mandate.ParameterNotNull(contentType, "contentType");
_contentType = contentType;
@@ -95,7 +111,7 @@ namespace Umbraco.Core.Models
/// </summary>
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
/// <param name="parentId"> </param>
internal void ChangeTrashedState(bool isTrashed, int parentId = -1)
public override void ChangeTrashedState(bool isTrashed, int parentId = -1)
{
Trashed = isTrashed;

View File

@@ -1,6 +1,7 @@
using System;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Models
{
@@ -13,7 +14,7 @@ namespace Umbraco.Core.Models
/// <returns>Xml of the property and its value</returns>
public static XElement ToXml(this Property property)
{
string nodeName = property.Alias.ToUmbracoAlias(StringAliasCaseType.CamelCase, true);
string nodeName = UmbracoSettings.UseLegacyXmlSchema ? "data" : property.Alias.ToSafeAlias();
var xd = new XmlDocument();
XmlNode xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");

View File

@@ -17,8 +17,9 @@ namespace Umbraco.Core.Models
private string _name;
private string _alias;
private string _description;
private int _dataTypeId;
private Guid _dataTypeControlId;
private int _dataTypeDefinitionId;
private int _propertyGroupId;
private Guid _dataTypeId;
private DataTypeDatabaseType _dataTypeDatabaseType;
private bool _mandatory;
private string _helpText;
@@ -28,9 +29,9 @@ namespace Umbraco.Core.Models
public PropertyType(IDataTypeDefinition dataTypeDefinition)
{
if(dataTypeDefinition.HasIdentity)
DataTypeId = dataTypeDefinition.Id;
DataTypeDefinitionId = dataTypeDefinition.Id;
DataTypeControlId = dataTypeDefinition.ControlId;
DataTypeId = dataTypeDefinition.ControlId;
DataTypeDatabaseType = dataTypeDefinition.DatabaseType;
EnsureSerializationService();
@@ -38,7 +39,7 @@ namespace Umbraco.Core.Models
internal PropertyType(Guid dataTypeControlId, DataTypeDatabaseType dataTypeDatabaseType)
{
DataTypeControlId = dataTypeControlId;
DataTypeId = dataTypeControlId;
DataTypeDatabaseType = dataTypeDatabaseType;
EnsureSerializationService();
@@ -53,13 +54,14 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Name);
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Alias);
private static readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Description);
private static readonly PropertyInfo DataTypeIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.DataTypeId);
private static readonly PropertyInfo DataTypeControlIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, Guid>(x => x.DataTypeControlId);
private static readonly PropertyInfo DataTypeDefinitionIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.DataTypeDefinitionId);
private static readonly PropertyInfo DataTypeControlIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, Guid>(x => x.DataTypeId);
private static readonly PropertyInfo DataTypeDatabaseTypeSelector = ExpressionHelper.GetPropertyInfo<PropertyType, DataTypeDatabaseType>(x => x.DataTypeDatabaseType);
private static readonly PropertyInfo MandatorySelector = ExpressionHelper.GetPropertyInfo<PropertyType, bool>(x => x.Mandatory);
private static readonly PropertyInfo HelpTextSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.HelpText);
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.SortOrder);
private static readonly PropertyInfo ValidationRegExpSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.ValidationRegExp);
private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.PropertyGroupId);
/// <summary>
/// Gets of Sets the Name of the PropertyType
@@ -108,13 +110,13 @@ namespace Umbraco.Core.Models
/// </summary>
/// <remarks>This is actually the Id of the <see cref="IDataTypeDefinition"/></remarks>
[DataMember]
public int DataTypeId
public int DataTypeDefinitionId
{
get { return _dataTypeId; }
get { return _dataTypeDefinitionId; }
set
{
_dataTypeId = value;
OnPropertyChanged(DataTypeIdSelector);
_dataTypeDefinitionId = value;
OnPropertyChanged(DataTypeDefinitionIdSelector);
}
}
@@ -123,12 +125,12 @@ namespace Umbraco.Core.Models
/// </summary>
/// <remarks>This is the Id of the actual DataType control</remarks>
[DataMember]
internal Guid DataTypeControlId
public Guid DataTypeId
{
get { return _dataTypeControlId; }
set
get { return _dataTypeId; }
internal set
{
_dataTypeControlId = value;
_dataTypeId = value;
OnPropertyChanged(DataTypeControlIdSelector);
}
}
@@ -147,6 +149,20 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or Sets the PropertyGroup's Id for which this PropertyType belongs
/// </summary>
[DataMember]
internal int PropertyGroupId
{
get { return _propertyGroupId; }
set
{
_propertyGroupId = value;
OnPropertyChanged(PropertyGroupIdSelector);
}
}
/// <summary>
/// Gets of Sets the Boolean indicating whether a value for this PropertyType is required
/// </summary>
@@ -280,7 +296,7 @@ namespace Umbraco.Core.Models
return argument == type;
}*/
if (DataTypeControlId != Guid.Empty)
if (DataTypeId != Guid.Empty)
{
//Find DataType by Id
//IDataType dataType = DataTypesResolver.Current.GetById(DataTypeControlId);

View File

@@ -19,8 +19,8 @@ namespace Umbraco.Core.Models
internal static IDataType DataType(this PropertyType propertyType, int propertyId)
{
Mandate.ParameterNotNull(propertyType, "propertyType");
var dataType = ApplicationContext.Current.Services.DataTypeService.GetDataTypeById(propertyType.DataTypeControlId);
dataType.DataTypeDefinitionId = propertyType.DataTypeId;
var dataType = ApplicationContext.Current.Services.DataTypeService.GetDataTypeById(propertyType.DataTypeId);
dataType.DataTypeDefinitionId = propertyType.DataTypeDefinitionId;
dataType.Data.PropertyId = propertyId;
return dataType;
}

View File

@@ -0,0 +1,9 @@
namespace Umbraco.Core.Models
{
public enum PublishedState
{
Published,
Unpublished,
Saved
}
}

View File

@@ -43,11 +43,6 @@ namespace Umbraco.Core.Models.Rdbms
[Constraint(Default = "0")]
public bool AllowAtRoot { get; set; }
[Column("masterContentType")]
[Constraint(Default = "0")]
[NullSetting(NullSetting = NullSettings.Null)]
public int MasterContentType { get; set; }//TODO Delete once "masterContentType" has been removed from the Core
[ResultColumn]
public NodeDto NodeDto { get; set; }
}

View File

@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models.Rdbms
public int ContentTypeNodeId { get; set; }
[Column("templateNodeId")]
/*[ForeignKey(typeof(TemplateDto))]*/
[ForeignKey(typeof(TemplateDto), Column = "nodeId")]
public int TemplateNodeId { get; set; }
[Column("IsDefault")]

View File

@@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.Caching;
using System.Threading;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Persistence.Caching
@@ -23,9 +24,10 @@ namespace Umbraco.Core.Persistence.Caching
#endregion
private readonly ObjectCache _memoryCache = new MemoryCache("in-memory");
//TODO Save this in cache as well, so its not limited to a single server usage
private ConcurrentDictionary<string, string> _keyTracker = new ConcurrentDictionary<string, string>();
private ObjectCache _memoryCache = new MemoryCache("in-memory");
private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
public IEntity GetById(Type type, Guid id)
{
@@ -77,6 +79,16 @@ namespace Umbraco.Core.Persistence.Caching
_keyTracker.TryRemove(key, out throwaway);
}
public void Clear()
{
using (new ReadLock(ClearLock))
{
_keyTracker.Clear();
_memoryCache.DisposeIfDisposable();
_memoryCache = new MemoryCache("in-memory");
}
}
private string GetCompositeId(Type type, Guid id)
{
return string.Format("{0}-{1}", type.Name, id.ToString());

View File

@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Factories
public IContent BuildEntity(DocumentDto dto)
{
return new Content(dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType)
return new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType)
{
Id = _id,
Key =
@@ -57,20 +57,23 @@ namespace Umbraco.Core.Persistence.Factories
public DocumentDto BuildDto(IContent entity)
{
//NOTE Currently doesn't add Alias and templateId (legacy stuff that eventually will go away)
//NOTE Currently doesn't add Alias (legacy that eventually will go away)
var documentDto = new DocumentDto
{
Newest = true,
NodeId = entity.Id,
Published = entity.Published,
Text = entity.Name,
UpdateDate = entity.UpdateDate,
WriterUserId = entity.WriterId,
VersionId = entity.Version,
ExpiresDate = null,
ReleaseDate = null,
ContentVersionDto = BuildContentVersionDto(entity)
};
{
Newest = true,
NodeId = entity.Id,
Published = entity.Published,
Text = entity.Name,
UpdateDate = entity.UpdateDate,
WriterUserId = entity.WriterId,
VersionId = entity.Version,
ExpiresDate = null,
ReleaseDate = null,
ContentVersionDto = BuildContentVersionDto(entity)
};
if (entity.Template != null && entity.Template.Id > 0)
documentDto.TemplateId = entity.Template.Id;
if (entity.ExpireDate.HasValue)
documentDto.ExpiresDate = entity.ExpireDate.Value;

View File

@@ -29,14 +29,13 @@ namespace Umbraco.Core.Persistence.Factories
public IMedia BuildEntity(ContentVersionDto dto)
{
return new Models.Media(dto.ContentDto.NodeDto.ParentId, _contentType)
return new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, _contentType)
{
Id = _id,
Key =
dto.ContentDto.NodeDto.UniqueId.HasValue
? dto.ContentDto.NodeDto.UniqueId.Value
: _id.ToGuid(),
Name = dto.ContentDto.NodeDto.Text,
Path = dto.ContentDto.NodeDto.Path,
CreatorId = dto.ContentDto.NodeDto.UserId.Value,
Level = dto.ContentDto.NodeDto.Level,

View File

@@ -32,13 +32,19 @@ namespace Umbraco.Core.Persistence.Factories
public IEnumerable<Property> BuildEntity(IEnumerable<PropertyDataDto> dtos)
{
var properties = new List<Property>();
foreach (var dto in dtos)
{
var propertyType = _contentType.CompositionPropertyTypes.FirstOrDefault(x => x.Id == dto.PropertyTypeId);
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
property.ResetDirtyProperties();
properties.Add(property);
if (_contentType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
{
var propertyType = _contentType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
property.ResetDirtyProperties();
properties.Add(property);
}
}
return properties;
}
@@ -95,10 +101,14 @@ namespace Umbraco.Core.Persistence.Factories
var properties = new List<Property>();
foreach (var dto in dtos)
{
var propertyType = _mediaType.PropertyTypes.FirstOrDefault(x => x.Id == dto.PropertyTypeId);
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
property.ResetDirtyProperties();
properties.Add(property);
if (_mediaType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
{
var propertyType = _mediaType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
property.ResetDirtyProperties();
properties.Add(property);
}
}
return properties;
}

View File

@@ -28,19 +28,22 @@ namespace Umbraco.Core.Persistence.Factories
group.SortOrder = groupDto.SortOrder;
group.PropertyTypes = new PropertyTypeCollection();
foreach (var typeDto in groupDto.PropertyTypeDtos)
//Because we are likely to have a group with no PropertyTypes we need to ensure that these are excluded
var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0);
foreach (var typeDto in typeDtos)
{
group.PropertyTypes.Add(new PropertyType(typeDto.DataTypeDto.ControlId,
typeDto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
{
Alias = typeDto.Alias,
DataTypeId = typeDto.DataTypeId,
DataTypeDefinitionId = typeDto.DataTypeId,
Description = typeDto.Description,
Id = typeDto.Id,
Name = typeDto.Name,
HelpText = typeDto.HelpText,
Mandatory = typeDto.Mandatory,
SortOrder = typeDto.SortOrder
SortOrder = typeDto.SortOrder,
PropertyGroupId = groupDto.Id
});
}
@@ -53,7 +56,7 @@ namespace Umbraco.Core.Persistence.Factories
public IEnumerable<PropertyTypeGroupDto> BuildDto(IEnumerable<PropertyGroup> entity)
{
return entity.Select(propertyGroup => BuildGroupDto(propertyGroup)).ToList();
return entity.Select(BuildGroupDto).ToList();
}
#endregion
@@ -82,15 +85,17 @@ namespace Umbraco.Core.Persistence.Factories
{
Alias = propertyType.Alias,
ContentTypeId = _id,
DataTypeId = propertyType.DataTypeId,
DataTypeId = propertyType.DataTypeDefinitionId,
Description = propertyType.Description,
HelpText = propertyType.HelpText,
Mandatory = propertyType.Mandatory,
Name = propertyType.Name,
SortOrder = propertyType.SortOrder,
PropertyTypeGroupId = tabId
SortOrder = propertyType.SortOrder
};
if (tabId != default(int))
propertyTypeDto.PropertyTypeGroupId = tabId;
if (propertyType.HasIdentity)
propertyTypeDto.Id = propertyType.Id;

View File

@@ -29,14 +29,14 @@ namespace Umbraco.Core.Persistence.Mappers
{
CacheMap<PropertyType, PropertyTypeDto>(src => src.Id, dto => dto.Id);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<PropertyType, PropertyTypeDto>(src => src.DataTypeId, dto => dto.DataTypeId);
CacheMap<PropertyType, PropertyTypeDto>(src => src.DataTypeDefinitionId, dto => dto.DataTypeId);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Description, dto => dto.Description);
CacheMap<PropertyType, PropertyTypeDto>(src => src.HelpText, dto => dto.HelpText);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Mandatory, dto => dto.Mandatory);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Name, dto => dto.Name);
CacheMap<PropertyType, PropertyTypeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<PropertyType, PropertyTypeDto>(src => src.ValidationRegExp, dto => dto.ValidationRegExp);
CacheMap<PropertyType, DataTypeDto>(src => src.DataTypeControlId, dto => dto.ControlId);
CacheMap<PropertyType, DataTypeDto>(src => src.DataTypeId, dto => dto.ControlId);
CacheMap<PropertyType, DataTypeDto>(src => src.DataTypeDatabaseType, dto => dto.DbType);
}
}

View File

@@ -6,5 +6,6 @@ namespace Umbraco.Core.Persistence.Migrations
{
ICollection<IMigrationExpression> Expressions { get; set; }
DatabaseProviders CurrentDatabaseProvider { get; }
Database Database { get; }
}
}

View File

@@ -11,61 +11,61 @@ namespace Umbraco.Core.Persistence.Migrations
{
public abstract class MigrationBase : IMigration
{
internal IMigrationContext _context;
internal IMigrationContext Context;
public abstract void Up();
public abstract void Down();
public virtual void GetUpExpressions(IMigrationContext context)
{
_context = context;
Context = context;
Up();
}
public virtual void GetDownExpressions(IMigrationContext context)
{
_context = context;
Context = context;
Down();
}
public IAlterSyntaxBuilder Alter
{
get { return new AlterSyntaxBuilder(_context); }
get { return new AlterSyntaxBuilder(Context); }
}
public ICreateBuilder Create
{
get { return new CreateBuilder(_context); }
get { return new CreateBuilder(Context); }
}
public IDeleteBuilder Delete
{
get { return new DeleteBuilder(_context); }
get { return new DeleteBuilder(Context); }
}
public IExecuteBuilder Execute
{
get { return new ExecuteBuilder(_context); }
get { return new ExecuteBuilder(Context); }
}
public IInsertBuilder Insert
{
get { return new InsertBuilder(_context); }
get { return new InsertBuilder(Context); }
}
public IRenameBuilder Rename
{
get { return new RenameBuilder(_context); }
get { return new RenameBuilder(Context); }
}
public IUpdateBuilder Update
{
get { return new UpdateBuilder(_context); }
get { return new UpdateBuilder(Context); }
}
public IIfDatabaseBuilder IfDatabase(params DatabaseProviders[] databaseProviders)
{
return new IfDatabaseBuilder(_context, databaseProviders);
return new IfDatabaseBuilder(Context, databaseProviders);
}
}
}

View File

@@ -5,14 +5,17 @@ namespace Umbraco.Core.Persistence.Migrations
{
internal class MigrationContext : IMigrationContext
{
public MigrationContext(DatabaseProviders databaseProvider)
public MigrationContext(DatabaseProviders databaseProvider, Database database)
{
Expressions = new Collection<IMigrationExpression>();
CurrentDatabaseProvider = databaseProvider;
Database = database;
}
public ICollection<IMigrationExpression> Expressions { get; set; }
public DatabaseProviders CurrentDatabaseProvider { get; private set; }
public Database Database { get; private set; }
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.ObjectResolution;
namespace Umbraco.Core.Persistence.Migrations
{
/// <summary>
/// A resolver to return all IMigrations
/// </summary>
internal class MigrationResolver : ManyObjectsResolverBase<MigrationResolver, IMigration>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="migrations"></param>
/// <remarks>
/// Use transient objects as we don't want these as singletons and take up memory that is not required
/// </remarks>
public MigrationResolver(IEnumerable<Type> migrations)
: base(migrations, ObjectLifetimeScope.Transient)
{
}
/// <summary>
/// Gets the migrations
/// </summary>
public IEnumerable<IMigration> Migrations
{
get { return Values; }
}
}
}

View File

@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Persistence.Migrations
{
/// <summary>
/// <summary>
/// Represents the Migration Runner, which is used to apply migrations to
/// the umbraco database.
/// </summary>
@@ -44,13 +45,17 @@ namespace Umbraco.Core.Persistence.Migrations
{
LogHelper.Info<MigrationRunner>("Initializing database migration");
var foundMigrations = PluginManager.Current.FindMigrations();
var foundMigrations = MigrationResolver.Current.Migrations;
var migrations = isUpgrade
? OrderedUpgradeMigrations(foundMigrations)
: OrderedDowngradeMigrations(foundMigrations);
? OrderedUpgradeMigrations(foundMigrations).ToList()
: OrderedDowngradeMigrations(foundMigrations).ToList();
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _configuredVersion, _targetVersion, true), this))
return false;
//Loop through migrations to generate sql
var context = new MigrationContext(databaseProvider);
var context = new MigrationContext(databaseProvider, database);
foreach (MigrationBase migration in migrations)
{
if (isUpgrade)
@@ -84,6 +89,8 @@ namespace Umbraco.Core.Persistence.Migrations
transaction.Complete();
}
Migrated.RaiseEvent(new MigrationEventArgs(migrations, context, _configuredVersion, _targetVersion, false), this);
return true;
}
@@ -114,5 +121,15 @@ namespace Umbraco.Core.Persistence.Migrations
select migration);
return migrations;
}
/// <summary>
/// Occurs before Migration
/// </summary>
public static event TypedEventHandler<MigrationRunner, MigrationEventArgs> Migrating;
/// <summary>
/// Occurs after Migration
/// </summary>
public static event TypedEventHandler<MigrationRunner, MigrationEventArgs> Migrated;
}
}

View File

@@ -1,13 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Persistence.Migrations
{
internal static class PluginManagerExtension
{
public static IEnumerable<IMigration> FindMigrations(this PluginManager resolver)
{
var types = resolver.ResolveTypesWithAttribute<IMigration, MigrationAttribute>();
return resolver.CreateInstances<IMigration>(types);
}
}
}

View File

@@ -5,15 +5,20 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
public class ExecuteBuilder : IExecuteBuilder
{
private readonly IMigrationContext _context;
private readonly DatabaseProviders[] _databaseProviders;
public ExecuteBuilder(IMigrationContext context)
public ExecuteBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
{
_context = context;
_databaseProviders = databaseProviders;
}
public void Sql(string sqlStatement)
{
var expression = new ExecuteSqlStatementExpression {SqlStatement = sqlStatement};
var expression = _databaseProviders == null
? new ExecuteSqlStatementExpression {SqlStatement = sqlStatement}
: new ExecuteSqlStatementExpression(_context.CurrentDatabaseProvider,
_databaseProviders) {SqlStatement = sqlStatement};
_context.Expressions.Add(expression);
}
}

View File

@@ -14,6 +14,9 @@
public override string ToString()
{
if (IsExpressionSupported() == false)
return string.Empty;
return SqlStatement;
}
}

View File

@@ -1,13 +1,17 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
using Umbraco.Core.Persistence.Migrations.Syntax.Delete;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute;
using Umbraco.Core.Persistence.Migrations.Syntax.Rename;
using Umbraco.Core.Persistence.Migrations.Syntax.Update;
namespace Umbraco.Core.Persistence.Migrations.Syntax.IfDatabase
{
public interface IIfDatabaseBuilder : IFluentSyntax
{
ICreateBuilder Create { get; }
IExecuteBuilder Execute { get; }
IDeleteBuilder Delete { get; }
IRenameBuilder Rename { get; }
IUpdateBuilder Update { get; }
}
}

View File

@@ -1,6 +1,8 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
using Umbraco.Core.Persistence.Migrations.Syntax.Delete;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute;
using Umbraco.Core.Persistence.Migrations.Syntax.Rename;
using Umbraco.Core.Persistence.Migrations.Syntax.Update;
namespace Umbraco.Core.Persistence.Migrations.Syntax.IfDatabase
{
@@ -20,6 +22,11 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.IfDatabase
get { return new CreateBuilder(_context, _databaseProviders); }
}
public IExecuteBuilder Execute
{
get { return new ExecuteBuilder(_context, _databaseProviders); }
}
public IDeleteBuilder Delete
{
get { return new DeleteBuilder(_context, _databaseProviders); }
@@ -29,5 +36,10 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.IfDatabase
{
get { return new RenameBuilder(_context, _databaseProviders); }
}
public IUpdateBuilder Update
{
get { return new UpdateBuilder(_context, _databaseProviders); }
}
}
}

View File

@@ -22,6 +22,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
public override string ToString()
{
if (IsExpressionSupported() == false)
return string.Empty;
var updateItems = new List<string>();
var whereClauses = new List<string>();

View File

@@ -5,15 +5,19 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update
public class UpdateBuilder : IUpdateBuilder
{
private readonly IMigrationContext _context;
private readonly DatabaseProviders[] _databaseProviders;
public UpdateBuilder(IMigrationContext context)
public UpdateBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
{
_context = context;
_databaseProviders = databaseProviders;
}
public IUpdateSetSyntax Table(string tableName)
{
var expression = new UpdateDataExpression { TableName = tableName };
var expression = _databaseProviders == null
? new UpdateDataExpression { TableName = tableName }
: new UpdateDataExpression(_context.CurrentDatabaseProvider, _databaseProviders) { TableName = tableName };
_context.Expressions.Add(expression);
return new UpdateDataBuilder(expression, _context);
}

View File

@@ -1,7 +1,7 @@
using System.Data;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourEightZero
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero
{
[MigrationAttribute("4.8.0", 0, GlobalSettings.UmbracoMigrationName)]
public class RemoveUmbracoAppConstraints : MigrationBase

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 10, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 10, GlobalSettings.UmbracoMigrationName)]
public class DeleteAppTables : MigrationBase
{
public override void Up()

View File

@@ -1,9 +1,9 @@
using System;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 9, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 9, GlobalSettings.UmbracoMigrationName)]
public class EnsureAppsTreesUpdated : MigrationBase
{
public override void Up()

View File

@@ -0,0 +1,29 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[Migration("6.0.0", 5, GlobalSettings.UmbracoMigrationName)]
public class MoveMasterContentTypeData : MigrationBase
{
public override void Up()
{
//Reading entries from the cmsContentType table in order to update the parentID on the umbracoNode table.
//NOTE This is primarily done because of a shortcoming in sql ce, which has really bad support for updates (can't use FROM or subqueries with multiple results).
if (base.Context != null && base.Context.Database != null)
{
var list = base.Context.Database.Fetch<dynamic>("SELECT nodeId, masterContentType FROM cmsContentType WHERE not masterContentType is null AND masterContentType != 0");
foreach (var item in list)
{
Update.Table("umbracoNode").Set(new { parentID = item.masterContentType }).Where(new { id = item.nodeId });
}
}
Execute.Sql(
"INSERT INTO cmsContentType2ContentType (parentContentTypeId, childContentTypeId) SELECT masterContentType, nodeId FROM cmsContentType WHERE not masterContentType is null and masterContentType != 0");
}
public override void Down()
{
}
}
}

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 4, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 4, GlobalSettings.UmbracoMigrationName)]
public class NewCmsContentType2ContentTypeTable : MigrationBase
{
public override void Up()

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 6, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 6, GlobalSettings.UmbracoMigrationName)]
public class RemoveMasterContentTypeColumn : MigrationBase
{
public override void Up()

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 0, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 0, GlobalSettings.UmbracoMigrationName)]
public class RenameCmsTabTable : MigrationBase
{
public override void Up()

View File

@@ -1,9 +1,9 @@
using System.Data;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 7, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 7, GlobalSettings.UmbracoMigrationName)]
public class RenameTabIdColumn : MigrationBase
{
public override void Up()

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 3, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 3, GlobalSettings.UmbracoMigrationName)]
public class UpdateCmsContentTypeAllowedContentTypeTable : MigrationBase
{
public override void Up()

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 2, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 2, GlobalSettings.UmbracoMigrationName)]
public class UpdateCmsContentTypeTable : MigrationBase
{
public override void Up()

View File

@@ -1,8 +1,8 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 8, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 8, GlobalSettings.UmbracoMigrationName)]
public class UpdateCmsContentVersionTable : MigrationBase
{
public override void Up()

View File

@@ -1,9 +1,9 @@
using System.Data;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix
{
[MigrationAttribute("6.0.0", 1, GlobalSettings.UmbracoMigrationName)]
[Migration("6.0.0", 1, GlobalSettings.UmbracoMigrationName)]
public class UpdateCmsPropertyTypeGroupTable : MigrationBase
{
public override void Up()

View File

@@ -1,18 +0,0 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth
{
[MigrationAttribute("6.0.0", 5, GlobalSettings.UmbracoMigrationName)]
public class MoveMasterContentTypeData : MigrationBase
{
public override void Up()
{
Execute.Sql(
"INSERT INTO cmsContentType2ContentType (parentContentTypeId, childContentTypeId) SELECT masterContentType, nodeId FROM cmsContentType WHERE not masterContentType is null and masterContentType != 0");
}
public override void Down()
{
}
}
}

View File

@@ -424,7 +424,14 @@ namespace Umbraco.Core.Persistence
}
else if (t == typeof(string))
{
p.Size = Math.Max((item as string).Length + 1, 4000); // Help query plan caching by using common size
// out of memory exception occurs if trying to save more than 4000 characters to SQL Server CE NText column. Set before attempting to set Size, or Size will always max out at 4000
if ((item as string).Length + 1 > 4000 && p.GetType().Name == "SqlCeParameter")
p.GetType().GetProperty("SqlDbType").SetValue(p, SqlDbType.NText, null);
p.Size = (item as string).Length + 1;
if(p.Size < 4000)
p.Size = Math.Max((item as string).Length + 1, 4000); // Help query plan caching by using common size
p.Value = item;
}
else if (t == typeof(AnsiString))

View File

@@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence
db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName))));
//Special case for MySql
if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql"))
if (SyntaxConfig.SqlSyntaxProvider is MySqlSyntaxProvider && tableName.Equals("umbracoUser"))
{
db.Update<UserDto>("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" });
}

View File

@@ -150,21 +150,18 @@ namespace Umbraco.Core.Persistence.Querying
protected virtual string VisitMemberAccess(MemberExpression m)
{
if (m.Expression != null &&
m.Expression.NodeType == ExpressionType.Parameter
&& m.Expression.Type == typeof(T))
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter && m.Expression.Type == typeof(T))
{
var field = _mapper.Map(m.Member.Name);
return field;
}
if (m.Expression != null && m.Expression.NodeType != ExpressionType.Constant)
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Convert)
{
var field = _mapper.Map(m.Member.Name);
return field;
}
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
@@ -190,9 +187,7 @@ namespace Umbraco.Core.Persistence.Querying
var r = new StringBuilder();
foreach (Object e in exprs)
{
r.AppendFormat("{0}{1}",
r.Length > 0 ? "," : "",
e);
r.AppendFormat("{0}{1}", r.Length > 0 ? "," : "", e);
}
return r.ToString();
}

View File

@@ -159,13 +159,12 @@ namespace Umbraco.Core.Persistence.Querying
return field;
}
if (m.Expression != null && m.Expression.NodeType != ExpressionType.Constant)
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Convert)
{
string field = GetFieldName(pd, m.Member.Name);
return field;
}
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();

View File

@@ -40,11 +40,11 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IContent PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var sql = GetBaseQuery(false)
.Where(GetBaseWhereClause(), new { Id = id })
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Query<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;
@@ -56,7 +56,7 @@ namespace Umbraco.Core.Persistence.Repositories
var content = factory.BuildEntity(dto);
//Check if template id is set on DocumentDto, and get ITemplate if it is.
if (dto.TemplateId.HasValue)
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
{
content.Template = _templateRepository.Get(dto.TemplateId.Value);
}
@@ -163,7 +163,7 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Query<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;
@@ -262,8 +262,9 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistUpdatedItem(IContent entity)
{
var publishedState = ((Content) entity).PublishedState;
//A new version should only be created if published state (or language) has changed
bool shouldCreateNewVersion = ((ICanBeDirty)entity).IsPropertyDirty("Published") || ((ICanBeDirty)entity).IsPropertyDirty("Language");
bool shouldCreateNewVersion = (((ICanBeDirty)entity).IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished) || ((ICanBeDirty)entity).IsPropertyDirty("Language");
if (shouldCreateNewVersion)
{
//Updates Modified date and Version Guid
@@ -274,11 +275,14 @@ namespace Umbraco.Core.Persistence.Repositories
entity.UpdateDate = DateTime.Now;
}
//Look up parent to get and set the correct Path if ParentId has changed
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
if (((ICanBeDirty)entity).IsPropertyDirty("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", new { ParentId = entity.ParentId });
entity.SortOrder = maxSortOrder;
}
var factory = new ContentFactory(NodeObjectTypeId, entity.Id);
@@ -299,8 +303,9 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Update(newContentDto);
}
//If Published state has changed then previous versions should have their publish state reset
if (((ICanBeDirty)entity).IsPropertyDirty("Published") && entity.Published)
//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))
{
var publishedDocs = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND published = @IsPublished", new { Id = entity.Id, IsPublished = true });
foreach (var doc in publishedDocs)
@@ -365,6 +370,8 @@ namespace Umbraco.Core.Persistence.Repositories
{
foreach (var property in entity.Properties)
{
if(keyDictionary.ContainsKey(property.PropertyTypeId) == false) continue;
property.Id = keyDictionary[property.PropertyTypeId];
}
}
@@ -379,7 +386,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Loop through properties to check if the content contains images/files that should be deleted
foreach (var property in entity.Properties)
{
if (property.PropertyType.DataTypeControlId == uploadFieldId &&
if (property.PropertyType.DataTypeId == uploadFieldId &&
string.IsNullOrEmpty(property.Value.ToString()) == false
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
{
@@ -413,7 +420,7 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Where<ContentVersionDto>(x => x.Language == language);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Query<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;

View File

@@ -40,7 +40,8 @@ namespace Umbraco.Core.Persistence.Repositories
.RightJoin<PropertyTypeDto>()
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId);
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId)
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId);
var translator = new SqlTranslator<PropertyType>(sqlClause, query);
var sql = translator.Translate();
@@ -130,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Update the current PropertyType with correct ControlId and DatabaseType
var dataTypeDto = Database.FirstOrDefault<DataTypeDto>("WHERE nodeId = @Id", new { Id = propertyTypeDto.DataTypeId });
propertyType.DataTypeControlId = dataTypeDto.ControlId;
propertyType.DataTypeId = dataTypeDto.ControlId;
propertyType.DataTypeDatabaseType = dataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true);
}
}
@@ -168,11 +169,19 @@ namespace Umbraco.Core.Persistence.Repositories
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
{
//Delete PropertyTypes by excepting entries from db with entries from collections
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id }).Select(x => x.Alias);
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias);
var aliases = dbPropertyTypes.Except(entityPropertyTypes);
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id });
var dbPropertyTypeAlias = dbPropertyTypes.Select(x => x.Alias.ToLowerInvariant());
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias.ToLowerInvariant());
var aliases = dbPropertyTypeAlias.Except(entityPropertyTypes);
foreach (var alias in aliases)
{
//Before a PropertyType can be deleted, all Properties based on that PropertyType should be deleted.
var propertyType = dbPropertyTypes.FirstOrDefault(x => x.Alias.ToLowerInvariant() == alias);
if (propertyType != null)
{
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new { Id = propertyType.Id });
}
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND Alias = @Alias", new { Id = entity.Id, Alias = alias });
}
//Delete Tabs/Groups by excepting entries from db with entries from collections
@@ -184,7 +193,7 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name", new { Id = entity.Id, Name = tabName });
}
//Run through all groups and types to insert or update entries
//Run through all groups to insert or update entries
foreach (var propertyGroup in entity.PropertyGroups)
{
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
@@ -193,19 +202,17 @@ namespace Umbraco.Core.Persistence.Repositories
: Convert.ToInt32(Database.Insert(tabDto));
if (!propertyGroup.HasIdentity)
propertyGroup.Id = groupPrimaryKey;//Set Id on new PropertyGroup
}
//This should indicate that neither group nor property types has been touched, but this implies a deeper 'Dirty'-lookup
//if(!propertyGroup.IsDirty()) continue;
foreach (var propertyType in propertyGroup.PropertyTypes)
{
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
int typePrimaryKey = propertyType.HasIdentity
? Database.Update(propertyTypeDto)
: Convert.ToInt32(Database.Insert(propertyTypeDto));
if (!propertyType.HasIdentity)
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
}
//Run through all PropertyTypes to insert or update entries
foreach (var propertyType in entity.PropertyTypes)
{
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyType.PropertyGroupId, propertyType);
int typePrimaryKey = propertyType.HasIdentity
? Database.Update(propertyTypeDto)
: Convert.ToInt32(Database.Insert(propertyTypeDto));
if (!propertyType.HasIdentity)
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
}
}
}
@@ -226,11 +233,12 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql();
sql.Select("*")
.From<PropertyTypeGroupDto>()
.RightJoin<PropertyTypeDto>()
.LeftJoin<PropertyTypeDto>()
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
.InnerJoin<DataTypeDto>()
.LeftJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId)
.Where<PropertyTypeDto>(x => x.ContentTypeId == id);
.Where<PropertyTypeGroupDto>(x => x.ContentTypeNodeId == id)
.OrderBy<PropertyTypeGroupDto>(x => x.Id);
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
@@ -238,5 +246,36 @@ namespace Umbraco.Core.Persistence.Repositories
var propertyGroups = propertyFactory.BuildEntity(dtos);
return new PropertyGroupCollection(propertyGroups);
}
protected PropertyTypeCollection GetPropertyTypeCollection(int id)
{
var sql = new Sql();
sql.Select("*")
.From<PropertyTypeDto>()
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId)
.Where<PropertyTypeDto>(x => x.ContentTypeId == id);
var dtos = Database.Fetch<PropertyTypeDto, DataTypeDto>(sql);
//TODO Move this to a PropertyTypeFactory
var list = (from dto in dtos
where (dto.PropertyTypeGroupId > 0) == false
select
new PropertyType(dto.DataTypeDto.ControlId,
dto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
{
Alias = dto.Alias,
DataTypeDefinitionId = dto.DataTypeId,
Description = dto.Description,
Id = dto.Id,
Name = dto.Name,
HelpText = dto.HelpText,
Mandatory = dto.Mandatory,
SortOrder = dto.SortOrder
});
return new PropertyTypeCollection(list);
}
}
}

View File

@@ -37,7 +37,11 @@ namespace Umbraco.Core.Persistence.Repositories
var contentTypeSql = GetBaseQuery(false);
contentTypeSql.Where(GetBaseWhereClause(), new { Id = id });
var dto = Database.Query<DocumentTypeDto, ContentTypeDto, NodeDto>(contentTypeSql).FirstOrDefault();
// The SQL will contain one record for each allowed template, so order to put the default one
// at the top to populate the default template property correctly.
contentTypeSql.OrderByDescending<DocumentTypeDto>(x => x.IsDefault);
var dto = Database.Fetch<DocumentTypeDto, ContentTypeDto, NodeDto>(contentTypeSql).FirstOrDefault();
if (dto == null)
return null;
@@ -47,12 +51,12 @@ namespace Umbraco.Core.Persistence.Repositories
contentType.AllowedContentTypes = GetAllowedContentTypeIds(id);
contentType.PropertyGroups = GetPropertyGroupCollection(id);
((ContentType)contentType).PropertyTypes = GetPropertyTypeCollection(id);
var templates = Database.Fetch<DocumentTypeDto>("WHERE contentTypeNodeId = @Id", new { Id = id });
if(templates.Any())
{
contentType.AllowedTemplates =
templates.Select(template => _templateRepository.Get(template.TemplateNodeId));
contentType.AllowedTemplates = templates.Select(template => _templateRepository.Get(template.TemplateNodeId)).ToList();
}
var list = Database.Fetch<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new { Id = id});
@@ -114,16 +118,14 @@ namespace Umbraco.Core.Persistence.Repositories
protected override Sql GetBaseQuery(bool isCount)
{
//TODO Investigate the proper usage of IsDefault on cmsDocumentType
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*")
.From<DocumentTypeDto>()
.RightJoin<ContentTypeDto>()
.On<ContentTypeDto, DocumentTypeDto>(left => left.NodeId, right => right.ContentTypeNodeId)
.InnerJoin<NodeDto>()
.On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<DocumentTypeDto>(x => x.IsDefault == true);
.From<DocumentTypeDto>()
.RightJoin<ContentTypeDto>()
.On<ContentTypeDto, DocumentTypeDto>(left => left.NodeId, right => right.ContentTypeNodeId)
.InnerJoin<NodeDto>()
.On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
}
@@ -170,9 +172,12 @@ namespace Umbraco.Core.Persistence.Repositories
var dto = factory.BuildDto(entity);
PersistNewBaseContentType(dto.ContentTypeDto, entity);
//Inserts data into the cmsDocumentType table
dto.ContentTypeNodeId = entity.Id;
Database.Insert(dto);
//Inserts data into the cmsDocumentType table if a template exists
if (dto.TemplateNodeId > 0)
{
dto.ContentTypeNodeId = entity.Id;
Database.Insert(dto);
}
//Insert allowed Templates not including the default one, as that has already been inserted
foreach (var template in entity.AllowedTemplates.Where(x => x != null && x.Id != dto.TemplateNodeId))
@@ -203,8 +208,11 @@ namespace Umbraco.Core.Persistence.Repositories
//Look up DocumentType entries for updating - this could possibly be a "remove all, insert all"-approach
Database.Delete<DocumentTypeDto>("WHERE contentTypeNodeId = @Id", new { Id = entity.Id});
Database.Insert(dto);
//Insert the updated DocumentTypeDto if a template exists
if (dto.TemplateNodeId > 0)
{
Database.Insert(dto);
}
//Insert allowed Templates not including the default one, as that has already been inserted
foreach (var template in entity.AllowedTemplates.Where(x => x != null && x.Id != dto.TemplateNodeId))

View File

@@ -34,7 +34,7 @@ namespace Umbraco.Core.Persistence.Repositories
var dataTypeSql = GetBaseQuery(false);
dataTypeSql.Where(GetBaseWhereClause(), new { Id = id });
var dataTypeDto = Database.Query<DataTypeDto, NodeDto>(dataTypeSql).FirstOrDefault();
var dataTypeDto = Database.Fetch<DataTypeDto, NodeDto>(dataTypeSql).FirstOrDefault();
if (dataTypeDto == null)
return null;

View File

@@ -35,8 +35,9 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IDictionaryItem PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
var sql = GetBaseQuery(false)
.Where(GetBaseWhereClause(), new {Id = id})
.OrderBy<DictionaryDto>(x => x.UniqueId);
var dto = Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql).FirstOrDefault();
if (dto == null)
@@ -83,6 +84,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IDictionaryItem>(sqlClause, query);
var sql = translator.Translate();
sql.OrderBy<DictionaryDto>(x => x.UniqueId);
var dtos = Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql);

View File

@@ -33,8 +33,8 @@ namespace Umbraco.Core.Persistence.Repositories
}
private void EnsureDependencies()
{
_fileSystem = FileSystemProviderManager.Current.GetFileSystemProvider("macros");
{
_fileSystem = new PhysicalFileSystem("~/App_Data/Macros");
var serviceStackSerializer = new ServiceStackJsonSerializer();
_serializationService = new SerializationService(serviceStackSerializer);
}

View File

@@ -41,7 +41,7 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Where(GetBaseWhereClause(), new { Id = id });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Query<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;
@@ -145,7 +145,7 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Query<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;
@@ -240,11 +240,14 @@ namespace Umbraco.Core.Persistence.Repositories
//Updates Modified date
((Models.Media)entity).UpdatingEntity();
//Look up parent to get and set the correct Path if ParentId has changed
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
if (((ICanBeDirty)entity).IsPropertyDirty("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", new { ParentId = entity.ParentId });
entity.SortOrder = maxSortOrder;
}
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
@@ -307,7 +310,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Loop through properties to check if the media item contains images/file that should be deleted
foreach (var property in entity.Properties)
{
if (property.PropertyType.DataTypeControlId == uploadFieldId &&
if (property.PropertyType.DataTypeId == uploadFieldId &&
string.IsNullOrEmpty(property.Value.ToString()) == false
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
{

View File

@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories
var contentTypeSql = GetBaseQuery(false);
contentTypeSql.Where(GetBaseWhereClause(), new { Id = id});
var dto = Database.Query<ContentTypeDto, NodeDto>(contentTypeSql).FirstOrDefault();
var dto = Database.Fetch<ContentTypeDto, NodeDto>(contentTypeSql).FirstOrDefault();
if (dto == null)
return null;
@@ -43,6 +43,7 @@ namespace Umbraco.Core.Persistence.Repositories
contentType.AllowedContentTypes = GetAllowedContentTypeIds(id);
contentType.PropertyGroups = GetPropertyGroupCollection(id);
((MediaType)contentType).PropertyTypes = GetPropertyTypeCollection(id);
var list = Database.Fetch<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new{ Id = id});
foreach (var contentTypeDto in list)

View File

@@ -14,8 +14,13 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal class ScriptRepository : FileRepository<string, Script>, IScriptRepository
{
internal ScriptRepository(IUnitOfWork work, IFileSystem fileSystem)
: base(work, fileSystem)
{
}
public ScriptRepository(IUnitOfWork work)
: base(work, FileSystemProviderManager.Current.GetFileSystemProvider("scripts"))
: this(work, new PhysicalFileSystem(SystemDirectories.Scripts))
{
}

View File

@@ -14,8 +14,14 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal class StylesheetRepository : FileRepository<string, Stylesheet>, IStylesheetRepository
{
internal StylesheetRepository(IUnitOfWork work, IFileSystem fileSystem)
: base(work, fileSystem)
{
}
public StylesheetRepository(IUnitOfWork work)
: base(work, FileSystemProviderManager.Current.GetFileSystemProvider("stylesheets"))
: this(work, new PhysicalFileSystem(SystemDirectories.Css))
{
}

View File

@@ -23,20 +23,20 @@ namespace Umbraco.Core.Persistence.Repositories
private IFileSystem _masterpagesFileSystem;
private IFileSystem _viewsFileSystem;
public TemplateRepository(IDatabaseUnitOfWork work)
: base(work)
public TemplateRepository(IDatabaseUnitOfWork work)
: base(work)
{
EnsureDepedencies();
}
public TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
public TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
EnsureDepedencies();
}
internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem)
: base(work, cache)
internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem)
: base(work, cache)
{
_masterpagesFileSystem = masterpageFileSystem;
_viewsFileSystem = viewFileSystem;
@@ -44,8 +44,8 @@ namespace Umbraco.Core.Persistence.Repositories
private void EnsureDepedencies()
{
_masterpagesFileSystem = FileSystemProviderManager.Current.GetFileSystemProvider("masterpages");
_viewsFileSystem = FileSystemProviderManager.Current.GetFileSystemProvider("views");
_masterpagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages);
_viewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
}
#region Overrides of RepositoryBase<int,ITemplate>
@@ -74,17 +74,20 @@ namespace Umbraco.Core.Persistence.Repositories
template.MasterTemplateId = dto.Master.Value;
}
if(_viewsFileSystem.FileExists(csViewName))
if (_viewsFileSystem.FileExists(csViewName))
{
PopulateViewTemplate(template, csViewName);
}
else if(_viewsFileSystem.FileExists(vbViewName))
else if (_viewsFileSystem.FileExists(vbViewName))
{
PopulateViewTemplate(template, vbViewName);
}
else
{
PopulateMasterpageTemplate(template, masterpageName);
if (_masterpagesFileSystem.FileExists(masterpageName))
{
PopulateMasterpageTemplate(template, masterpageName);
}
}
return template;
@@ -164,9 +167,9 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistNewItem(ITemplate entity)
{
using(var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content)))
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content)))
{
if(entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc)
if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc)
{
_viewsFileSystem.AddFile(entity.Name, stream, true);
}
@@ -337,7 +340,7 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<ITemplate> GetAll(params string[] aliases)
{
if(aliases.Any())
if (aliases.Any())
{
foreach (var id in aliases)
{
@@ -352,7 +355,7 @@ namespace Umbraco.Core.Persistence.Repositories
yield return Get(nodeDto.NodeId);
}
}
}
#endregion

View File

@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
@@ -23,9 +25,16 @@ namespace Umbraco.Core.Persistence.Repositories
public virtual IEnumerable<TEntity> GetAllVersions(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var sql = new Sql();
sql.Select("*")
.From<ContentVersionDto>()
.InnerJoin<ContentDto>()
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.NodeId == id)
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql);
foreach (var dto in dtos)

View File

@@ -41,11 +41,21 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public override bool DoesTableExist(Database db, string tableName)
{
db.OpenSharedConnection();
var result =
db.ExecuteScalar<long>("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES " +
"WHERE TABLE_NAME = @TableName AND " +
"TABLE_SCHEMA = @TableSchema", new { TableName = tableName, TableSchema = db.Connection.Database });
long result;
try
{
db.OpenSharedConnection();
result =
db.ExecuteScalar<long>("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES " +
"WHERE TABLE_NAME = @TableName AND " +
"TABLE_SCHEMA = @TableSchema",
new {TableName = tableName, TableSchema = db.Connection.Database});
}
finally
{
db.CloseSharedConnection();
}
return result > 0;
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Data;
using System.Data.Common;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Persistence
{
@@ -14,10 +15,7 @@ namespace Umbraco.Core.Persistence
/// </remarks>
public class UmbracoDatabase : Database
{
private readonly Guid _instanceId = Guid.NewGuid();
private readonly Guid _instanceId = Guid.NewGuid();
/// <summary>
/// Used for testing
/// </summary>
@@ -41,5 +39,11 @@ namespace Umbraco.Core.Persistence
public UmbracoDatabase(string connectionStringName) : base(connectionStringName)
{
}
public override void OnException(Exception x)
{
LogHelper.Info<UmbracoDatabase>(x.StackTrace);
base.OnException(x);
}
}
}

View File

@@ -11,6 +11,7 @@ using System.Xml.Linq;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.PropertyEditors;
using umbraco.interfaces;
using File = System.IO.File;
@@ -458,6 +459,15 @@ namespace Umbraco.Core
return ResolveTypes<IMacroPropertyType>();
}
/// <summary>
/// Returns all available IMigrations in application
/// </summary>
/// <returns></returns>
internal IEnumerable<Type> ResolveMigrationTypes()
{
return ResolveTypes<IMigration>();
}
/// <summary>
/// Gets/sets which assemblies to scan when type finding, generally used for unit testing, if not explicitly set
/// this will search all assemblies known to have plugins and exclude ones known to not have them.

View File

@@ -38,4 +38,5 @@ using System.Security.Permissions;
[assembly: InternalsVisibleTo("Umbraco.Core")]
[assembly: InternalsVisibleTo("Umbraco.Web")]
[assembly: InternalsVisibleTo("Umbraco.Web.UI")]
[assembly: InternalsVisibleTo("UmbracoExamine")]
[assembly: InternalsVisibleTo("UmbracoExamine")]
[assembly: InternalsVisibleTo("Umbraco.Courier.Persistence")]

View File

@@ -54,7 +54,7 @@ namespace Umbraco.Core.Publishing
return false;
}
content.ChangePublishedState(true);
content.ChangePublishedState(PublishedState.Published);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been published.",
@@ -106,7 +106,7 @@ namespace Umbraco.Core.Publishing
continue;
}
item.ChangePublishedState(true);
item.ChangePublishedState(PublishedState.Published);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been published.",
@@ -138,8 +138,8 @@ namespace Umbraco.Core.Publishing
"Content '{0}' with Id '{1}' had its release date removed, because it was unpublished.",
content.Name, content.Id));
}
content.ChangePublishedState(false);
content.ChangePublishedState(PublishedState.Unpublished);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
@@ -173,7 +173,7 @@ namespace Umbraco.Core.Publishing
item.Name, item.Id));
}
item.ChangePublishedState(false);
item.ChangePublishedState(PublishedState.Unpublished);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been unpublished.",

View File

@@ -59,15 +59,16 @@ namespace Umbraco.Core.Services
_repositoryFactory = repositoryFactory;
}
/// <summary>
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
/// that this Content is based on.
/// </summary>
/// <param name="parentId">Id of Parent for the new Content</param>
/// <param name="contentTypeAlias">Alias of the <see cref="IContentType"/></param>
/// <param name="userId">Optional id of the user creating the content</param>
/// <returns><see cref="IContent"/></returns>
public IContent CreateContent(int parentId, string contentTypeAlias, int userId = -1)
/// <summary>
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
/// that this Content is based on.
/// </summary>
/// <param name="name">Name of the Content object</param>
/// <param name="parentId">Id of Parent for the new Content</param>
/// <param name="contentTypeAlias">Alias of the <see cref="IContentType"/></param>
/// <param name="userId">Optional id of the user creating the content</param>
/// <returns><see cref="IContent"/></returns>
public IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = -1)
{
IContentType contentType = null;
IContent content = null;
@@ -89,7 +90,7 @@ namespace Umbraco.Core.Services
contentTypeAlias));
}
content = new Content(parentId, contentType);
content = new Content(name, parentId, contentType);
if (Creating.IsRaisedEventCancelled(new NewEventArgs<IContent>(content, contentTypeAlias, parentId), this))
return content;
@@ -245,7 +246,7 @@ namespace Umbraco.Core.Services
{
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path));
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path) && x.Id != content.Id);
var contents = repository.GetByQuery(query);
return contents;
@@ -375,63 +376,10 @@ namespace Umbraco.Core.Services
/// Re-Publishes all Content
/// </summary>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool RePublishAll(int userId = -1, bool omitCacheRefresh = false)
public bool RePublishAll(int userId = -1)
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
var list = new List<IContent>();
var updated = new List<IContent>();
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
var rootContent = GetRootContent();
foreach (var content in rootContent)
{
if (content.IsValid())
{
list.Add(content);
list.AddRange(GetChildrenDeep(content.Id));
}
}
//Publish and then update the database with new status
var published = _publishingStrategy.PublishWithChildren(list, userId);
if (published)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Only loop through content where the Published property has been updated
foreach (var item in list.Where(x => ((ICanBeDirty) x).IsPropertyDirty("Published")))
{
SetWriter(item, userId);
repository.AddOrUpdate(item);
updated.Add(item);
}
uow.Commit();
foreach (var c in updated)
{
var xml = c.ToXml();
var poco = new ContentXmlDto {NodeId = c.Id, Xml = xml.ToString(SaveOptions.None)};
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new {Id = c.Id}) !=
null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
//Updating content to published state is finished, so we fire event through PublishingStrategy to have cache updated
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(updated, true);
}
Audit.Add(AuditTypes.Publish, "RePublish All performed by user", userId == -1 ? 0 : userId, -1);
return published;
return RePublishAllDo(false, userId);
}
/// <summary>
@@ -439,12 +387,10 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool Publish(IContent content, int userId = -1, bool omitCacheRefresh = false)
public bool Publish(IContent content, int userId = -1)
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
return SaveAndPublish(content, userId, omitCacheRefresh);
return SaveAndPublishDo(content, false, userId);
}
/// <summary>
@@ -452,76 +398,10 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool PublishWithChildren(IContent content, int userId = -1, bool omitCacheRefresh = false)
public bool PublishWithChildren(IContent content, int userId = -1)
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false)
{
LogHelper.Info<ContentService>(
string.Format(
"Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.",
content.Name, content.Id));
return false;
}
//Content contains invalid property values and can therefore not be published - fire event?
if (!content.IsValid())
{
LogHelper.Info<ContentService>(
string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
content.Name, content.Id));
return false;
}
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path));
var updated = new List<IContent>();
var list = new List<IContent>();
list.Add(content);
list.AddRange(GetChildrenDeep(content.Id));
//Publish and then update the database with new status
var published = _publishingStrategy.PublishWithChildren(list, userId);
if (published)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Only loop through content where the Published property has been updated
foreach (var item in list.Where(x => ((ICanBeDirty) x).IsPropertyDirty("Published")))
{
SetWriter(item, userId);
repository.AddOrUpdate(item);
updated.Add(item);
}
uow.Commit();
foreach (var c in updated)
{
var xml = c.ToXml();
var poco = new ContentXmlDto {NodeId = c.Id, Xml = xml.ToString(SaveOptions.None)};
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new {Id = c.Id}) !=
null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
//Save xml to db and call following method to fire event:
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(updated, false);
Audit.Add(AuditTypes.Publish, "Publish with Children performed by user", userId == -1 ? 0 : userId,
content.Id);
}
return published;
return PublishWithChildrenDo(content, false, userId);
}
/// <summary>
@@ -529,33 +409,10 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.</param>
/// <returns>True if unpublishing succeeded, otherwise False</returns>
public bool UnPublish(IContent content, int userId = -1, bool omitCacheRefresh = false)
public bool UnPublish(IContent content, int userId = -1)
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
var unpublished = _publishingStrategy.UnPublish(content, userId);
if (unpublished)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
repository.AddOrUpdate(content);
//Remove 'published' xml from the cmsContentXml table for the unpublished content
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new {Id = content.Id});
uow.Commit();
}
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
if (omitCacheRefresh == false)
_publishingStrategy.UnPublishingFinalized(content);
Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId == -1 ? 0 : userId, content.Id);
}
return unpublished;
return UnPublishDo(content, false, userId);
}
/// <summary>
@@ -563,76 +420,10 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
public bool SaveAndPublish(IContent content, int userId = -1, bool omitCacheRefresh = false)
public bool SaveAndPublish(IContent content, int userId = -1)
{
//TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons.
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
return false;
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false)
{
LogHelper.Info<ContentService>(
string.Format(
"Content '{0}' with Id '{1}' could not be published because its parent is not published.",
content.Name, content.Id));
return false;
}
//Content contains invalid property values and can therefore not be published - fire event?
if (!content.IsValid())
{
LogHelper.Info<ContentService>(
string.Format(
"Content '{0}' with Id '{1}' could not be published because of invalid properties.",
content.Name, content.Id));
return false;
}
//Publish and then update the database with new status
bool published = _publishingStrategy.Publish(content, userId);
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed
SetWriter(content, userId);
repository.AddOrUpdate(content);
uow.Commit();
if (published)
{
var xml = content.ToXml();
var poco = new ContentXmlDto { NodeId = content.Id, Xml = xml.ToString(SaveOptions.None) };
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new {Id = content.Id}) != null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(content);
//We need to check if children and their publish state to ensure that we republish content that was previously published
if (HasChildren(content.Id))
{
var children = GetChildrenDeep(content.Id);
var shouldBeRepublished = children.Where(child => HasPublishedVersion(child.Id));
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(shouldBeRepublished, false);
}
Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId == -1 ? 0 : userId, content.Id);
return published;
return SaveAndPublishDo(content, false, userId);
}
/// <summary>
@@ -642,25 +433,7 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the User saving the Content</param>
public void Save(IContent content, int userId = -1)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
SetWriter(content, userId);
//Only change the publish state if the "previous" version was actually published
if (content.Published)
content.ChangePublishedState(false);
repository.AddOrUpdate(content);
uow.Commit();
}
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id);
Save(content, true, userId);
}
/// <summary>
@@ -690,7 +463,7 @@ namespace Umbraco.Core.Services
//Only change the publish state if the "previous" version was actually published
if (content.Published)
content.ChangePublishedState(false);
content.ChangePublishedState(PublishedState.Saved);
repository.AddOrUpdate(content);
uow.Commit();
@@ -893,52 +666,90 @@ namespace Umbraco.Core.Services
}
/// <summary>
/// Moves an <see cref="IContent"/> object to a new location by changing its parent id.
/// </summary>
/// <remarks>
/// If the <see cref="IContent"/> object is already published it will be
/// published after being moved to its new location. Otherwise it'll just
/// be saved with a new parent id.
/// </remarks>
/// <param name="content">The <see cref="IContent"/> to move</param>
/// <param name="parentId">Id of the Content's new Parent</param>
/// <param name="userId">Optional Id of the User moving the Content</param>
public void Move(IContent content, int parentId, int userId = -1)
{
//TODO Verify that SortOrder + Path is updated correctly
//TODO Add a check to see if parentId = -20 because then we should change the TrashState
if (Moving.IsRaisedEventCancelled(new MoveEventArgs<IContent>(content, parentId), this))
return;
SetWriter(content, userId);
/// Moves an <see cref="IContent"/> object to a new location by changing its parent id.
/// </summary>
/// <remarks>
/// If the <see cref="IContent"/> object is already published it will be
/// published after being moved to its new location. Otherwise it'll just
/// be saved with a new parent id.
/// </remarks>
/// <param name="content">The <see cref="IContent"/> to move</param>
/// <param name="parentId">Id of the Content's new Parent</param>
/// <param name="userId">Optional Id of the User moving the Content</param>
public void Move(IContent content, int parentId, int userId = -1)
{
//This ensures that the correct method is called if this method is used to Move to recycle bin.
if (parentId == -20)
{
MoveToRecycleBin(content, userId);
return;
}
//If Content is being moved away from Recycle Bin, its state should be un-trashed
if (content.Trashed && parentId != -20)
{
content.ChangeTrashedState(false, parentId);
}
else
{
content.ParentId = parentId;
}
if (Moving.IsRaisedEventCancelled(new MoveEventArgs<IContent>(content, parentId), this))
return;
//If Content is published, it should be (re)published from its new location
if (content.Published)
{
SaveAndPublish(content, userId);
}
else
{
Save(content, userId);
}
SetWriter(content, userId);
var parent = GetById(parentId);
content.Path = string.Concat(parent.Path, ",", content.Id);
content.Level = parent.Level + 1;
Moved.RaiseEvent(new MoveEventArgs<IContent>(content, false, parentId), this);
//If Content is being moved away from Recycle Bin, its state should be un-trashed
if (content.Trashed && parentId != -20)
{
content.ChangeTrashedState(false, parentId);
}
else
{
content.ParentId = parentId;
}
//If Content is published, it should be (re)published from its new location
if (content.Published)
{
//If Content is Publishable its saved and published
//otherwise we save the content without changing the publish state, and generate new xml because the Path, Level and Parent has changed.
if (IsPublishable(content))
{
SaveAndPublish(content, userId);
}
else
{
Save(content, false, userId);
using (var uow = _uowProvider.GetUnitOfWork())
{
var xml = content.ToXml();
var poco = new ContentXmlDto {NodeId = content.Id, Xml = xml.ToString(SaveOptions.None)};
var exists =
uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new {Id = content.Id}) !=
null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
}
else
{
Save(content, userId);
}
//Ensure that Path and Level is updated on children
var children = GetChildren(content.Id);
if (children.Any())
{
foreach (var child in children)
{
Move(child, content.Id, userId);
}
}
Moved.RaiseEvent(new MoveEventArgs<IContent>(content, false, parentId), this);
Audit.Add(AuditTypes.Move, "Move Content performed by user", userId == -1 ? 0 : userId, content.Id);
}
/// <summary>
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
/// </summary>
public void EmptyRecycleBin()
@@ -982,7 +793,7 @@ namespace Umbraco.Core.Services
// A copy should never be set to published
// automatically even if the original was
this.UnPublish(copy);
this.UnPublish(copy, userId);
if (Copying.IsRaisedEventCancelled(new CopyEventArgs<IContent>(content, copy, parentId), this))
return null;
@@ -996,13 +807,13 @@ namespace Umbraco.Core.Services
uow.Commit();
var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
if (content.Properties.Any(x => x.PropertyType.DataTypeControlId == uploadFieldId))
if (content.Properties.Any(x => x.PropertyType.DataTypeId == uploadFieldId))
{
bool isUpdated = false;
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
//Loop through properties to check if the content contains media that should be deleted
foreach (var property in content.Properties.Where(x => x.PropertyType.DataTypeControlId == uploadFieldId
foreach (var property in content.Properties.Where(x => x.PropertyType.DataTypeId == uploadFieldId
&& string.IsNullOrEmpty(x.Value.ToString()) == false))
{
if (fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
@@ -1133,10 +944,344 @@ namespace Umbraco.Core.Services
{
_httpContext = httpContext;
}
/// <summary>
/// Internal method to Re-Publishes all Content for legacy purposes.
/// </summary>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will not update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
internal bool RePublishAll(bool omitCacheRefresh = true, int userId = -1)
{
return RePublishAllDo(omitCacheRefresh, userId);
}
/// <summary>
/// Internal method that Publishes a single <see cref="IContent"/> object for legacy purposes.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
internal bool Publish(IContent content, bool omitCacheRefresh = true, int userId = -1)
{
return SaveAndPublishDo(content, omitCacheRefresh, userId);
}
/// <summary>
/// Internal method that Publishes a <see cref="IContent"/> object and all its children for legacy purposes.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
internal bool PublishWithChildren(IContent content, bool omitCacheRefresh = true, int userId = -1)
{
return PublishWithChildrenDo(content, omitCacheRefresh, userId);
}
/// <summary>
/// Internal method that UnPublishes a single <see cref="IContent"/> object for legacy purposes.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will not update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if unpublishing succeeded, otherwise False</returns>
internal bool UnPublish(IContent content, bool omitCacheRefresh = true, int userId = -1)
{
return UnPublishDo(content, omitCacheRefresh, userId);
}
/// <summary>
/// Saves and Publishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
internal bool SaveAndPublish(IContent content, bool omitCacheRefresh = true, int userId = -1)
{
return SaveAndPublishDo(content, omitCacheRefresh, userId);
}
#endregion
#region Private Methods
/// <summary>
/// Re-Publishes all Content
/// </summary>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
private bool RePublishAllDo(bool omitCacheRefresh = false, int userId = -1)
{
var list = new List<IContent>();
var updated = new List<IContent>();
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
var rootContent = GetRootContent();
foreach (var content in rootContent)
{
if (content.IsValid())
{
list.Add(content);
list.AddRange(GetChildrenDeep(content.Id));
}
}
//Publish and then update the database with new status
var published = _publishingStrategy.PublishWithChildren(list, userId);
if (published)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Only loop through content where the Published property has been updated
foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published")))
{
SetWriter(item, userId);
repository.AddOrUpdate(item);
updated.Add(item);
}
uow.Commit();
foreach (var c in updated)
{
var xml = c.ToXml();
var poco = new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) };
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = c.Id }) !=
null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
//Updating content to published state is finished, so we fire event through PublishingStrategy to have cache updated
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(updated, true);
}
Audit.Add(AuditTypes.Publish, "RePublish All performed by user", userId == -1 ? 0 : userId, -1);
return published;
}
/// <summary>
/// Publishes a <see cref="IContent"/> object and all its children
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
private bool PublishWithChildrenDo(IContent content, bool omitCacheRefresh = false, int userId = -1)
{
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false)
{
LogHelper.Info<ContentService>(
string.Format(
"Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.",
content.Name, content.Id));
return false;
}
//Content contains invalid property values and can therefore not be published - fire event?
if (!content.IsValid())
{
LogHelper.Info<ContentService>(
string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
content.Name, content.Id));
return false;
}
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path));
var updated = new List<IContent>();
var list = new List<IContent>();
list.Add(content);
list.AddRange(GetChildrenDeep(content.Id));
//Publish and then update the database with new status
var published = _publishingStrategy.PublishWithChildren(list, userId);
if (published)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Only loop through content where the Published property has been updated
foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published")))
{
SetWriter(item, userId);
repository.AddOrUpdate(item);
updated.Add(item);
}
uow.Commit();
foreach (var c in updated)
{
var xml = c.ToXml();
var poco = new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) };
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = c.Id }) !=
null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
//Save xml to db and call following method to fire event:
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(updated, false);
Audit.Add(AuditTypes.Publish, "Publish with Children performed by user", userId == -1 ? 0 : userId,
content.Id);
}
return published;
}
/// <summary>
/// UnPublishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if unpublishing succeeded, otherwise False</returns>
private bool UnPublishDo(IContent content, bool omitCacheRefresh = false, int userId = -1)
{
var unpublished = _publishingStrategy.UnPublish(content, userId);
if (unpublished)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
repository.AddOrUpdate(content);
//Remove 'published' xml from the cmsContentXml table for the unpublished content
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = content.Id });
uow.Commit();
}
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
if (omitCacheRefresh == false)
_publishingStrategy.UnPublishingFinalized(content);
Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId == -1 ? 0 : userId, content.Id);
}
return unpublished;
}
/// <summary>
/// Saves and Publishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
private bool SaveAndPublishDo(IContent content, bool omitCacheRefresh = false, int userId = -1)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
return false;
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false)
{
LogHelper.Info<ContentService>(
string.Format(
"Content '{0}' with Id '{1}' could not be published because its parent is not published.",
content.Name, content.Id));
return false;
}
//Content contains invalid property values and can therefore not be published - fire event?
if (!content.IsValid())
{
LogHelper.Info<ContentService>(
string.Format(
"Content '{0}' with Id '{1}' could not be published because of invalid properties.",
content.Name, content.Id));
return false;
}
//Publish and then update the database with new status
bool published = _publishingStrategy.Publish(content, userId);
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed
SetWriter(content, userId);
repository.AddOrUpdate(content);
uow.Commit();
if (published)
{
var xml = content.ToXml();
var poco = new ContentXmlDto { NodeId = content.Id, Xml = xml.ToString(SaveOptions.None) };
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = content.Id }) != null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
}
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(content);
//We need to check if children and their publish state to ensure that we republish content that was previously published
if (HasChildren(content.Id))
{
var children = GetChildrenDeep(content.Id);
var shouldBeRepublished = children.Where(child => HasPublishedVersion(child.Id));
if (omitCacheRefresh == false)
_publishingStrategy.PublishingFinalized(shouldBeRepublished, false);
}
Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId == -1 ? 0 : userId, content.Id);
return published;
}
/// <summary>
/// Saves a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save</param>
/// <param name="changeState">Boolean indicating whether or not to change the Published state upon saving</param>
/// <param name="userId">Optional Id of the User saving the Content</param>
private void Save(IContent content, bool changeState, int userId = -1)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
SetWriter(content, userId);
//Only change the publish state if the "previous" version was actually published
if (changeState && content.Published)
content.ChangePublishedState(PublishedState.Saved);
repository.AddOrUpdate(content);
uow.Commit();
}
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id);
}
/// <summary>
/// Gets a flat list of decendents of content from parent id
/// </summary>
@@ -1189,7 +1334,7 @@ namespace Umbraco.Core.Services
if (checkCurrent == false && id == content.Id) continue;
//Check if the content for the current id is published - escape the loop if we encounter content that isn't published
var hasPublishedVersion = ApplicationContext.Current.Services.ContentService.GetById(id).Published;
var hasPublishedVersion = HasPublishedVersion(id);
if (hasPublishedVersion == false)
return false;
}

View File

@@ -153,7 +153,7 @@ namespace Umbraco.Core.Services
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
//Find ContentTypes using this IDataTypeDefinition on a PropertyType
var query = Query<PropertyType>.Builder.Where(x => x.DataTypeId == dataTypeDefinition.Id);
var query = Query<PropertyType>.Builder.Where(x => x.DataTypeDefinitionId == dataTypeDefinition.Id);
var contentTypes = repository.GetByQuery(query);
//Loop through the list of results and remove the PropertyTypes that references the DataTypeDefinition that is being deleted
@@ -163,7 +163,7 @@ namespace Umbraco.Core.Services
foreach (var group in contentType.PropertyGroups)
{
var types = @group.PropertyTypes.Where(x => x.DataTypeId == dataTypeDefinition.Id);
var types = @group.PropertyTypes.Where(x => x.DataTypeDefinitionId == dataTypeDefinition.Id);
foreach (var propertyType in types)
{
@group.PropertyTypes.Remove(propertyType);

View File

@@ -13,11 +13,12 @@ namespace Umbraco.Core.Services
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
/// that this Content is based on.
/// </summary>
/// <param name="name">Name of the Content object</param>
/// <param name="parentId">Id of Parent for the new Content</param>
/// <param name="contentTypeAlias">Alias of the <see cref="IContentType"/></param>
/// <param name="userId">Optional id of the user creating the content</param>
/// <returns><see cref="IContent"/></returns>
IContent CreateContent(int parentId, string contentTypeAlias, int userId = -1);
IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = -1);
/// <summary>
/// Gets an <see cref="IContent"/> object by Id
@@ -209,45 +210,40 @@ namespace Umbraco.Core.Services
/// Re-Publishes all Content
/// </summary>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
bool RePublishAll(int userId = -1, bool omitCacheRefresh = false);
bool RePublishAll(int userId = -1);
/// <summary>
/// Publishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
bool Publish(IContent content, int userId = -1, bool omitCacheRefresh = false);
bool Publish(IContent content, int userId = -1);
/// <summary>
/// Publishes a <see cref="IContent"/> object and all its children
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
bool PublishWithChildren(IContent content, int userId = -1, bool omitCacheRefresh = false);
bool PublishWithChildren(IContent content, int userId = -1);
/// <summary>
/// UnPublishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.</param>
/// <returns>True if unpublishing succeeded, otherwise False</returns>
bool UnPublish(IContent content, int userId = -1, bool omitCacheRefresh = false);
bool UnPublish(IContent content, int userId = -1);
/// <summary>
/// Saves and Publishes a single <see cref="IContent"/> object
/// </summary>
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
bool SaveAndPublish(IContent content, int userId = -1, bool omitCacheRefresh = false);
bool SaveAndPublish(IContent content, int userId = -1);
/// <summary>
/// Permanently deletes an <see cref="IContent"/> object.

View File

@@ -13,11 +13,12 @@ namespace Umbraco.Core.Services
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
/// that this Media is based on.
/// </summary>
/// <param name="name">Name of the Media object</param>
/// <param name="parentId">Id of Parent for the new Media item</param>
/// <param name="mediaTypeAlias">Alias of the <see cref="IMediaType"/></param>
/// <param name="userId">Optional id of the user creating the media item</param>
/// <returns><see cref="IMedia"/></returns>
IMedia CreateMedia(int parentId, string mediaTypeAlias, int userId = -1);
IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = -1);
/// <summary>
/// Gets an <see cref="IMedia"/> object by Id

View File

@@ -44,11 +44,12 @@ namespace Umbraco.Core.Services
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
/// that this Media is based on.
/// </summary>
/// <param name="name">Name of the Media object</param>
/// <param name="parentId">Id of Parent for the new Media item</param>
/// <param name="mediaTypeAlias">Alias of the <see cref="IMediaType"/></param>
/// <param name="userId">Optional id of the user creating the media item</param>
/// <returns><see cref="IMedia"/></returns>
public IMedia CreateMedia(int parentId, string mediaTypeAlias, int userId = -1)
public IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = -1)
{
IMediaType mediaType = null;
var uow = _uowProvider.GetUnitOfWork();
@@ -68,7 +69,7 @@ namespace Umbraco.Core.Services
mediaTypeAlias));
}
var media = new Models.Media(parentId, mediaType);
var media = new Models.Media(name, parentId, mediaType);
if (Creating.IsRaisedEventCancelled(new NewEventArgs<IMedia>(media, mediaTypeAlias, parentId), this))
return media;
@@ -262,12 +263,29 @@ namespace Umbraco.Core.Services
/// <param name="userId">Id of the User moving the Media</param>
public void Move(IMedia media, int parentId, int userId = -1)
{
//This ensures that the correct method is called if this method is used to Move to recycle bin.
if (parentId == -21)
{
MoveToRecycleBin(media, userId);
return;
}
if (Moving.IsRaisedEventCancelled(new MoveEventArgs<IMedia>(media, parentId), this))
return;
media.ParentId = parentId;
Save(media, userId);
//Ensure that Path and Level is updated on children
var children = GetChildren(media.Id);
if (children.Any())
{
var parentPath = media.Path;
var parentLevel = media.Level;
var updatedDescendents = UpdatePathAndLevelOnChildren(children, parentPath, parentLevel);
Save(updatedDescendents, userId);
}
Moved.RaiseEvent(new MoveEventArgs<IMedia>(media, false, parentId), this);
Audit.Add(AuditTypes.Move, "Move Media performed by user", userId == -1 ? 0 : userId, media.Id);
@@ -280,14 +298,20 @@ namespace Umbraco.Core.Services
/// <param name="userId">Id of the User deleting the Media</param>
public void MoveToRecycleBin(IMedia media, int userId = -1)
{
//TODO If media item has children those should also be moved to the recycle bin as well
if (Trashing.IsRaisedEventCancelled(new MoveEventArgs<IMedia>(media, -21), this))
if (Trashing.IsRaisedEventCancelled(new MoveEventArgs<IMedia>(media, -21), this))
return;
//Move children to Recycle Bin before the 'possible parent' is moved there
var children = GetChildren(media.Id);
foreach (var child in children)
{
MoveToRecycleBin(child, userId);
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
{
((Core.Models.Media)media).ChangeTrashedState(true);
media.ChangeTrashedState(true);
repository.AddOrUpdate(media);
uow.Commit();
}
@@ -499,6 +523,32 @@ namespace Umbraco.Core.Services
_httpContext = httpContext;
}
/// <summary>
/// Updates the Path and Level on a collection of <see cref="IMedia"/> objects
/// based on the Parent's Path and Level.
/// </summary>
/// <param name="children">Collection of <see cref="IMedia"/> objects to update</param>
/// <param name="parentPath">Path of the Parent media</param>
/// <param name="parentLevel">Level of the Parent media</param>
/// <returns>Collection of updated <see cref="IMedia"/> objects</returns>
private List<IMedia> UpdatePathAndLevelOnChildren(IEnumerable<IMedia> children, string parentPath, int parentLevel)
{
var list = new List<IMedia>();
foreach (var child in children)
{
child.Path = string.Concat(parentPath, ",", child.Id);
child.Level = parentLevel + 1;
list.Add(child);
var grandkids = GetChildren(child.Id);
if (grandkids.Any())
{
list.AddRange(UpdatePathAndLevelOnChildren(grandkids, child.Path, child.Level));
}
}
return list;
}
/// <summary>
/// Updates a media object with the User (id), who created the content.
/// </summary>

View File

@@ -11,6 +11,7 @@ using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using Umbraco.Core.Configuration;
using System.Web.Security;
namespace Umbraco.Core
{
@@ -20,47 +21,57 @@ namespace Umbraco.Core
///</summary>
public static class StringExtensions
{
//this is from SqlMetal and just makes it a bit of fun to allow pluralisation
public static string MakePluralName(this string name)
{
if ((name.EndsWith("x", StringComparison.OrdinalIgnoreCase) || name.EndsWith("ch", StringComparison.OrdinalIgnoreCase)) || (name.EndsWith("ss", StringComparison.OrdinalIgnoreCase) || name.EndsWith("sh", StringComparison.OrdinalIgnoreCase)))
{
name = name + "es";
return name;
}
if ((name.EndsWith("y", StringComparison.OrdinalIgnoreCase) && (name.Length > 1)) && !IsVowel(name[name.Length - 2]))
{
name = name.Remove(name.Length - 1, 1);
name = name + "ies";
return name;
}
if (!name.EndsWith("s", StringComparison.OrdinalIgnoreCase))
{
name = name + "s";
}
return name;
}
public static string EncryptWithMachineKey(this string toEncrypt)
{
var output = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, "temp", DateTime.Now, DateTime.MaxValue, false, toEncrypt));
return output;
}
public static string DecryptWithMachineKey(this string encrypted)
{
var output = FormsAuthentication.Decrypt(encrypted);
return output.UserData;
}
//this is from SqlMetal and just makes it a bit of fun to allow pluralisation
public static string MakePluralName(this string name)
{
if ((name.EndsWith("x", StringComparison.OrdinalIgnoreCase) || name.EndsWith("ch", StringComparison.OrdinalIgnoreCase)) || (name.EndsWith("ss", StringComparison.OrdinalIgnoreCase) || name.EndsWith("sh", StringComparison.OrdinalIgnoreCase)))
{
name = name + "es";
return name;
}
if ((name.EndsWith("y", StringComparison.OrdinalIgnoreCase) && (name.Length > 1)) && !IsVowel(name[name.Length - 2]))
{
name = name.Remove(name.Length - 1, 1);
name = name + "ies";
return name;
}
if (!name.EndsWith("s", StringComparison.OrdinalIgnoreCase))
{
name = name + "s";
}
return name;
}
public static bool IsVowel(this char c)
{
switch (c)
{
case 'O':
case 'U':
case 'Y':
case 'A':
case 'E':
case 'I':
case 'o':
case 'u':
case 'y':
case 'a':
case 'e':
case 'i':
return true;
}
return false;
}
public static bool IsVowel(this char c)
{
switch (c)
{
case 'O':
case 'U':
case 'Y':
case 'A':
case 'E':
case 'I':
case 'o':
case 'u':
case 'y':
case 'a':
case 'e':
case 'i':
return true;
}
return false;
}
/// <summary>
/// Trims the specified value from a string; accepts a string input whereas the in-built implementation only accepts char or char[].
@@ -74,49 +85,49 @@ namespace Umbraco.Core
return value.TrimEnd(forRemoving).TrimStart(forRemoving);
}
public static string EncodeJsString(this string s)
{
var sb = new StringBuilder();
foreach (var c in s)
{
switch (c)
{
case '\"':
sb.Append("\\\"");
break;
case '\\':
sb.Append("\\\\");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
default:
int i = (int)c;
if (i < 32 || i > 127)
{
sb.AppendFormat("\\u{0:X04}", i);
}
else
{
sb.Append(c);
}
break;
}
}
return sb.ToString();
}
public static string EncodeJsString(this string s)
{
var sb = new StringBuilder();
foreach (var c in s)
{
switch (c)
{
case '\"':
sb.Append("\\\"");
break;
case '\\':
sb.Append("\\\\");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
default:
int i = (int)c;
if (i < 32 || i > 127)
{
sb.AppendFormat("\\u{0:X04}", i);
}
else
{
sb.Append(c);
}
break;
}
}
return sb.ToString();
}
public static string TrimEnd(this string value, string forRemoving)
{
@@ -144,25 +155,25 @@ namespace Umbraco.Core
return toStartWith + input.TrimStart(toStartWith.ToArray()); // Ensure each char is removed first from input, e.g. ~/ plus /Path will equal ~/Path not ~//Path
}
public static string EnsureStartsWith(this string input, char value)
{
return input.StartsWith(value.ToString()) ? input : value + input;
}
public static string EnsureStartsWith(this string input, char value)
{
return input.StartsWith(value.ToString()) ? input : value + input;
}
public static string EnsureEndsWith(this string input, char value)
{
return input.EndsWith(value.ToString()) ? input : input + value;
}
public static string EnsureEndsWith(this string input, char value)
{
return input.EndsWith(value.ToString()) ? input : input + value;
}
public static bool IsLowerCase(this char ch)
{
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToLower();
}
public static bool IsUpperCase(this char ch)
{
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToUpper();
}
public static bool IsUpperCase(this char ch)
{
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToUpper();
}
/// <summary>Is null or white space.</summary>
/// <param name="str">The str.</param>
@@ -479,10 +490,10 @@ namespace Umbraco.Core
return String.Equals(compare, compareTo, StringComparison.InvariantCultureIgnoreCase);
}
public static bool InvariantStartsWith(this string compare, string compareTo)
{
return compare.StartsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
}
public static bool InvariantStartsWith(this string compare, string compareTo)
{
return compare.StartsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
}
public static bool InvariantContains(this string compare, string compareTo)
{
@@ -697,7 +708,7 @@ namespace Umbraco.Core
.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
return currentFolder;
}
/// <summary>
/// Truncates the specified text string.
@@ -760,5 +771,54 @@ namespace Umbraco.Core
return newUrl;
}
/// <summary>
/// An extention method to ensure that an Alias string doesn't contains any illegal characters
/// which is defined in a private constant 'ValidCharacters' in this class.
/// Conventions over configuration, baby. You can't touch this - MC Hammer!
/// </summary>
/// <remarks>
/// Copied and cleaned up a bit from umbraco.cms.helpers.Casing.
/// </remarks>
/// <param name="alias">The alias.</param>
/// <returns>An alias guaranteed not to contain illegal characters</returns>
public static string ToSafeAlias(this string alias)
{
const string validAliasCharacters = "_-abcdefghijklmnopqrstuvwxyz1234567890";
const string invalidFirstCharacters = "01234567890";
var safeString = new StringBuilder();
int aliasLength = alias.Length;
for (int i = 0; i < aliasLength; i++)
{
string currentChar = alias.Substring(i, 1);
if (validAliasCharacters.Contains(currentChar.ToLower()))
{
// check for camel (if previous character is a space, we'll upper case the current one
if (safeString.Length == 0 && invalidFirstCharacters.Contains(currentChar.ToLower()))
{
currentChar = "";
}
else
{
if (i < aliasLength - 1 && i > 0 && alias.Substring(i - 1, 1) == " ")
currentChar = currentChar.ToUpper();
safeString.Append(currentChar);
}
}
}
return safeString.ToString();
}
public static string ToSafeAliasWithForcingCheck(this string alias)
{
if (UmbracoSettings.ForceSafeAliases)
{
return alias.ToSafeAlias();
}
return alias;
}
}
}

View File

@@ -31,6 +31,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Umbraco.Core.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
@@ -118,6 +119,7 @@
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
<Compile Include="Dynamics\DynamicInstanceHelper.cs" />
<Compile Include="Dynamics\DynamicXmlConverter.cs" />
<Compile Include="Events\CancellableEventArgs.cs" />
<Compile Include="Events\ContentCacheEventArgs.cs" />
<Compile Include="Events\CopyEventArgs.cs" />
@@ -125,6 +127,7 @@
<Compile Include="Events\CancellableObjectEventArgs.cs" />
<Compile Include="Events\DeleteRevisionsEventArgs.cs" />
<Compile Include="Events\EventExtensions.cs" />
<Compile Include="Events\MigrationEventArgs.cs" />
<Compile Include="Events\PublishEventArgs.cs" />
<Compile Include="Events\TypedEventHandler.cs" />
<Compile Include="Events\MoveEventArgs.cs" />
@@ -181,6 +184,7 @@
<Compile Include="Models\PropertyExtensions.cs" />
<Compile Include="Models\PropertyTypeExtensions.cs" />
<Compile Include="Models\PublishedItemType.cs" />
<Compile Include="Models\PublishedState.cs" />
<Compile Include="Models\Rdbms\ContentType2ContentTypeDto.cs" />
<Compile Include="Models\Rdbms\PropertyTypeGroupDto.cs" />
<Compile Include="Models\Relation.cs" />
@@ -265,8 +269,8 @@
<Compile Include="Persistence\Migrations\MigrationBase.cs" />
<Compile Include="Persistence\Migrations\MigrationContext.cs" />
<Compile Include="Persistence\Migrations\MigrationExpressionBase.cs" />
<Compile Include="Persistence\Migrations\MigrationResolver.cs" />
<Compile Include="Persistence\Migrations\MigrationRunner.cs" />
<Compile Include="Persistence\Migrations\PluginManagerExtension.cs" />
<Compile Include="Persistence\Migrations\Syntax\Alter\AlterSyntaxBuilder.cs" />
<Compile Include="Persistence\Migrations\Syntax\Alter\Column\AlterColumnBuilder.cs" />
<Compile Include="Persistence\Migrations\Syntax\Alter\Column\IAlterColumnOptionForeignKeyCascadeSyntax.cs" />
@@ -372,18 +376,18 @@
<Compile Include="Persistence\Migrations\Syntax\Update\IUpdateWhereSyntax.cs" />
<Compile Include="Persistence\Migrations\Syntax\Update\UpdateBuilder.cs" />
<Compile Include="Persistence\Migrations\Syntax\Update\UpdateDataBuilder.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionFourEightZero\RemoveUmbracoAppConstraints.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\DeleteAppTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\EnsureAppsTreesUpdated.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\MoveMasterContentTypeData.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\NewCmsContentType2ContentTypeTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\RemoveMasterContentTypeColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\RenameTabIdColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\UpdateCmsContentTypeAllowedContentTypeTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\UpdateCmsContentTypeTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\UpdateCmsContentVersionTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\UpdateCmsPropertyTypeGroupTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixth\RenameCmsTabTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionFourNineZero\RemoveUmbracoAppConstraints.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\DeleteAppTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\EnsureAppsTreesUpdated.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\MoveMasterContentTypeData.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\NewCmsContentType2ContentTypeTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\RemoveMasterContentTypeColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\RenameTabIdColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\UpdateCmsContentTypeAllowedContentTypeTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\UpdateCmsContentTypeTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\UpdateCmsContentVersionTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\UpdateCmsPropertyTypeGroupTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\RenameCmsTabTable.cs" />
<Compile Include="Persistence\PetaPocoExtensions.cs" />
<Compile Include="Persistence\PetaPocoSqlExtensions.cs" />
<Compile Include="Persistence\Querying\PocoToSqlExpressionHelper.cs" />

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Core
/// <param name="text">The text.</param>
/// <param name="xmlDoc">The XML doc.</param>
/// <returns></returns>
internal static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc)
public static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc)
{
xmlDoc.LoadXml(text);
return xmlDoc.FirstChild;
@@ -80,7 +80,7 @@ namespace Umbraco.Core
/// <param name="name">The node name.</param>
/// <param name="value">The node value.</param>
/// <returns>A XmlNode</returns>
public static XmlNode AddCDataNode(XmlDocument xd, string name, string value)
public static XmlNode AddCDataNode(XmlDocument xd, string name, string value)
{
var temp = xd.CreateNode(XmlNodeType.Element, name, "");
temp.AppendChild(xd.CreateCDataSection(value));
@@ -92,7 +92,7 @@ namespace Umbraco.Core
/// </summary>
/// <param name="n">The XmlNode.</param>
/// <returns>the value as a string</returns>
internal static string GetNodeValue(XmlNode n)
public static string GetNodeValue(XmlNode n)
{
var value = string.Empty;
if (n == null || n.FirstChild == null)
@@ -108,7 +108,7 @@ namespace Umbraco.Core
/// <returns>
/// <c>true</c> if the specified string appears to be XML; otherwise, <c>false</c>.
/// </returns>
internal static bool CouldItBeXml(string xml)
public static bool CouldItBeXml(string xml)
{
if (!string.IsNullOrEmpty(xml))
{
@@ -131,7 +131,7 @@ namespace Umbraco.Core
/// <param name="rootName">Name of the root.</param>
/// <param name="elementName">Name of the element.</param>
/// <returns>Returns an <c>System.Xml.XmlDocument</c> representation of the delimited string data.</returns>
internal static XmlDocument Split(string data, string[] separator, string rootName, string elementName)
public static XmlDocument Split(string data, string[] separator, string rootName, string elementName)
{
return Split(new XmlDocument(), data, separator, rootName, elementName);
}
@@ -145,7 +145,7 @@ namespace Umbraco.Core
/// <param name="rootName">Name of the root node.</param>
/// <param name="elementName">Name of the element node.</param>
/// <returns>Returns an <c>System.Xml.XmlDocument</c> representation of the delimited string data.</returns>
internal static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName)
public static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName)
{
// load new XML document.
xml.LoadXml(string.Concat("<", rootName, "/>"));
@@ -174,7 +174,7 @@ namespace Umbraco.Core
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
internal static Dictionary<string, string> GetAttributesFromElement(string tag)
public static Dictionary<string, string> GetAttributesFromElement(string tag)
{
var m =
Regex.Matches(tag, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",

View File

@@ -39,7 +39,7 @@ namespace Umbraco.Tests.BusinessLogic
private void ClearDatabase()
{
var databaseSettings = ConfigurationManager.ConnectionStrings[Core.Configuration.GlobalSettings.UmbracoConnectionName];
var dataHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString) as SqlCEHelper;
var dataHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString, false) as SqlCEHelper;
if (dataHelper == null)
throw new InvalidOperationException("The sql helper for unit tests must be of type SqlCEHelper, check the ensure the connection string used for this test is set to use SQLCE");
@@ -57,7 +57,7 @@ namespace Umbraco.Tests.BusinessLogic
AppDomain.CurrentDomain.SetData("DataDirectory", TestHelper.CurrentAssemblyDirectory);
var databaseSettings = ConfigurationManager.ConnectionStrings[Core.Configuration.GlobalSettings.UmbracoConnectionName];
var dataHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString) as SqlCEHelper;
var dataHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString, false) as SqlCEHelper;
var installer = dataHelper.Utility.CreateInstaller();
if (installer.CanConnect)

View File

@@ -29,6 +29,7 @@ namespace Umbraco.Tests.ContentStores
PublishedMediaTests.DoTearDown();
}
[Ignore]
[Test]
public void Get_Root_Docs()
{
@@ -47,6 +48,7 @@ namespace Umbraco.Tests.ContentStores
}
[Ignore]
[Test]
public void Get_Item_Without_Examine()
{

View File

@@ -30,6 +30,7 @@ namespace Umbraco.Tests
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "");
}
[Ignore]
[Test]
public void Is_Version_From_Assembly_Correct()
{

View File

@@ -110,6 +110,7 @@ namespace Umbraco.Tests.IO
_fileSystem.DeleteDirectory("test", true);
}
[Ignore]
[Test]
public void Can_Get_File_Dates()
{

View File

@@ -13,6 +13,13 @@ namespace Umbraco.Tests.IO
public class IOHelperTest
{
[Test]
public void IOHelper_ResolveUrl()
{
var result = IOHelper.ResolveUrl("~/Scripts");
Assert.AreEqual("/Scripts", result);
}
/// <summary>
///A test for MapPath verifying that HttpContext method (which includes vdirs) matches non-HttpContext method
///</summary>

View File

@@ -3,6 +3,8 @@ using System.Linq;
using NUnit.Framework;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.datatype;
using umbraco.cms.businesslogic.media;
namespace Umbraco.Tests.LegacyApi
@@ -37,6 +39,49 @@ namespace Umbraco.Tests.LegacyApi
Assert.That(updated.AllowedChildContentTypeIDs.Any(x => x == 1045), Is.True);
}
[Test]
public void Can_Set_Tab_On_PropertyType()
{
var UPLOAD_DATATYPE_ID = -90;
var CROP_DATATYPE_ID = 1043;
var LABEL_DATATYPE_ID = -92;
var mediaTypeName = "ImageWide";
MediaType mediaType = MediaType.MakeNew(new User(0), mediaTypeName);
int imageTab = mediaType.AddVirtualTab("Image");
int cropTab = mediaType.AddVirtualTab("Crop");
mediaType.AddPropertyType(new DataTypeDefinition(UPLOAD_DATATYPE_ID), "umbracoFile", "Upload image");
mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoWidth", "Width");
mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoHeight", "Height");
mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoBytes", "Size");
mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoExtension", "Type");
mediaType.AddPropertyType(new DataTypeDefinition(CROP_DATATYPE_ID), "wideImage", "Wide image");
mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoFile"), imageTab);
mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoWidth"), imageTab);
mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoHeight"), imageTab);
mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoBytes"), imageTab);
mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoExtension"), imageTab);
mediaType.SetTabOnPropertyType(mediaType.getPropertyType("wideImage"), cropTab);
mediaType.Text = mediaTypeName;
mediaType.IconUrl = "mediaPhoto.gif";
mediaType.Save();
Assert.That(mediaType.getVirtualTabs.Count(), Is.EqualTo(2));
Assert.That(mediaType.getVirtualTabs.Any(x => x.Caption.Equals("Image")), Is.True);
Assert.That(mediaType.getVirtualTabs.Any(x => x.Caption.Equals("Crop")), Is.True);
var updated = new MediaType(mediaType.Id);
Assert.That(updated.getVirtualTabs.Count(), Is.EqualTo(2));
Assert.That(updated.getVirtualTabs.Any(x => x.Caption.Equals("Image")), Is.True);
Assert.That(updated.getVirtualTabs.Any(x => x.Caption.Equals("Crop")), Is.True);
Assert.That(updated.ContentTypeItem.PropertyGroups.Count(), Is.EqualTo(2));
Assert.That(updated.ContentTypeItem.PropertyTypes.Count(), Is.EqualTo(6));
}
public void CreateTestData()
{
//Create and Save ContentType "video" -> 1045

View File

@@ -21,7 +21,7 @@ namespace Umbraco.Tests.Migrations
public void Can_Get_Up_Migration_From_MigrationStub()
{
// Arrange
var context = new MigrationContext(DatabaseProviders.SqlServerCE);
var context = new MigrationContext(DatabaseProviders.SqlServerCE, null);
var stub = new AlterUserTableMigrationStub();
// Act

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -19,31 +20,25 @@ namespace Umbraco.Tests.Migrations
{
TestHelper.SetupLog4NetForTests();
//this ensures its reset
PluginManager.Current = new PluginManager(false);
MigrationResolver.Current = new MigrationResolver(new List<Type>
{
typeof (AlterUserTableMigrationStub),
typeof(Dummy),
typeof (FourNineMigration),
typeof (FourTenMigration),
typeof (FourElevenMigration),
typeof (FourElevenMigration)
});
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
PluginManager.Current.AssembliesToScan = new[]
{
typeof (FourNineMigration).Assembly
};
Resolution.Freeze();
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
}
[Test]
public void Can_Find_Migrations_In_Current_Assembly()
{
var foundTypes = PluginManager.Current.ResolveMigrationTypes();
Assert.That(foundTypes.Any(), Is.True);
Assert.That(foundTypes.Count(), Is.EqualTo(4));
}
}
[Test]
public void Can_Find_Migrations_With_Targtet_Version_Six()
{
var foundMigrations = PluginManager.Current.FindMigrations();
var foundMigrations = MigrationResolver.Current.Migrations;
var targetVersion = new Version("6.0.0");
var list = new List<IMigration>();
@@ -61,7 +56,7 @@ namespace Umbraco.Tests.Migrations
Assert.That(list.Count, Is.EqualTo(3));
var context = new MigrationContext(DatabaseProviders.SqlServerCE);
var context = new MigrationContext(DatabaseProviders.SqlServerCE, null);
foreach (MigrationBase migration in list)
{
migration.GetUpExpressions(context);
@@ -78,8 +73,9 @@ namespace Umbraco.Tests.Migrations
[TearDown]
public void TearDown()
{
PluginManager.Current = null;
{
MigrationResolver.Reset();
Resolution.IsFrozen = false;
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Persistence.Migrations;
namespace Umbraco.Tests.Migrations
{
/// <summary>
/// Used for TypeInheritanceTest and CodeFirstTests
/// </summary>
internal static class PluginManagerExtensions
{
public static IEnumerable<Type> ResolveMigrationTypes(this PluginManager resolver)
{
return resolver.ResolveTypesWithAttribute<IMigration, MigrationAttribute>();
}
public static IEnumerable<IMigration> FindMigrations(this PluginManager resolver)
{
var types = resolver.ResolveTypesWithAttribute<IMigration, MigrationAttribute>();
return resolver.CreateInstances<IMigration>(types);
}
}
}

View File

@@ -86,23 +86,47 @@ namespace Umbraco.Tests.Migrations.SqlScripts {
}
/// <summary>
/// Looks up a localized string similar to /*******************************************************************************************
/// Looks up a localized string similar to -- Script Date: 10-01-2013 11:50 - Generated by ExportSqlCe version 3.5.2.18
///-- Database information:
///-- Locale Identifier: 1030
///-- Encryption Mode:
///-- Case Sensitive: False
///-- Database: C:\Temp\Playground\Umb4110Starterkit\Umb4110Starterkit\App_Data\Umbraco.sdf
///-- ServerVersion: 4.0.8876.1
///-- DatabaseSize: 1114112
///-- Created: 10-01-2013 11:39
///
///
///
///
///
///
///
/// Umbraco database installation script for SQL Server CE 4
///-- User Table information:
///-- Number of tables: 43
///-- cmsContent: 12 row(s)
///-- cmsContentType: 10 row(s)
///-- cmsContentTypeAllowedContentType: 8 row(s [rest of string was truncated]&quot;;.
/// </summary>
internal static string SqlCe_SchemaAndData_4110 {
get {
return ResourceManager.GetString("SqlCe_SchemaAndData_4110", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to CREATE TABLE [umbracoRelation]
///(
///[id] [int] NOT NULL IDENTITY(1, 1),
///[parentId] [int] NOT NULL,
///[childId] [int] NOT NULL,
///[relType] [int] NOT NULL,
///[datetime] [datetime] NOT NULL CONSTRAINT [DF_umbracoRelation_datetime] DEFAULT (getdate()),
///[comment] [nvarchar] (1000) NOT NULL
///)
///
///IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT
///
/// Database version: 4.8.0.1
///
/// Please increment this version number if ANY change is made to this script,
/// so compatibility with scripts for other database systems can be verified easily.
/// The first 3 digits depict the Umbraco [rest of string was truncated]&quot;;.
///;
///ALTER TABLE [umbracoRelation] ADD CONSTRAINT [PK_umbracoRelation] PRIMARY KEY ([id])
///;
///CREATE TABLE [cmsDocument]
///(
///[nodeId] [int] NOT NULL,
///[published] [bit] NOT NULL,
///[documentUser] [int] NOT [rest of string was truncated]&quot;;.
/// </summary>
internal static string SqlCeTotal_480 {
get {

View File

@@ -124,6 +124,9 @@
<data name="SqlCeTotal_480" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>sqlcetotal-480.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="SqlCe_SchemaAndData_4110" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>sqlce-schemaanddata-4110.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
</data>
<data name="SqlServerTotal_480" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>sqlservertotal-480.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>

View File

@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Tests.TestHelpers;
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
@@ -18,38 +21,38 @@ namespace Umbraco.Tests.Migrations
{
TestHelper.SetupLog4NetForTests();
//this ensures its reset
PluginManager.Current = new PluginManager(false);
MigrationResolver.Current = new MigrationResolver(new List<Type>
{
typeof (Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero.RemoveUmbracoAppConstraints),
typeof (DeleteAppTables),
typeof (EnsureAppsTreesUpdated),
typeof (MoveMasterContentTypeData),
typeof (NewCmsContentType2ContentTypeTable),
typeof (RemoveMasterContentTypeColumn),
typeof (RenameCmsTabTable),
typeof (RenameTabIdColumn),
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
typeof (UpdateCmsContentTypeTable),
typeof (UpdateCmsContentVersionTable),
typeof (UpdateCmsPropertyTypeGroupTable)
});
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
PluginManager.Current.AssembliesToScan = new[]
{
typeof (MigrationRunner).Assembly
};
Resolution.Freeze();
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
}
[Test]
public void Can_Find_Migrations_In_Current_Assembly()
{
var foundTypes = PluginManager.Current.ResolveMigrationTypes();
Assert.That(foundTypes.Any(), Is.True);
Assert.That(foundTypes.Count(), Is.GreaterThanOrEqualTo(11));
}
[Test]
public void Can_Find_Targetted_Migrations()
{
var configuredVersion = new Version("4.11.0");
var targetVersion = new Version("6.0.0");
var foundMigrations = PluginManager.Current.FindMigrations();
var foundMigrations = MigrationResolver.Current.Migrations;
var migrationRunner = new MigrationRunner(configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
var migrations = migrationRunner.OrderedUpgradeMigrations(foundMigrations);
var context = new MigrationContext(DatabaseProviders.SqlServerCE);
var context = new MigrationContext(DatabaseProviders.SqlServerCE, null);
foreach (MigrationBase migration in migrations)
{
migration.GetUpExpressions(context);
@@ -66,7 +69,8 @@ namespace Umbraco.Tests.Migrations
[TearDown]
public void TearDown()
{
PluginManager.Current = null;
MigrationResolver.Reset();
Resolution.IsFrozen = false;
}
}
}

View File

@@ -1,12 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Strategies.Migrations;
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
namespace Umbraco.Tests.Migrations.Upgrades
@@ -15,7 +19,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
public abstract class BaseUpgradeTest
{
/// <summary>Regular expression that finds multiline block comments.</summary>
private static readonly Regex m_findComments = new Regex(@"\/\*.*?\*\/", RegexOptions.Singleline | RegexOptions.Compiled);
private static readonly Regex FindComments = new Regex(@"\/\*.*?\*\/", RegexOptions.Singleline | RegexOptions.Compiled);
[SetUp]
public virtual void Initialize()
@@ -27,15 +31,24 @@ namespace Umbraco.Tests.Migrations.Upgrades
AppDomain.CurrentDomain.SetData("DataDirectory", Path);
UmbracoSettings.UseLegacyXmlSchema = false;
MigrationResolver.Current = new MigrationResolver(new List<Type>
{
typeof (Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero.RemoveUmbracoAppConstraints),
typeof (DeleteAppTables),
typeof (EnsureAppsTreesUpdated),
typeof (MoveMasterContentTypeData),
typeof (NewCmsContentType2ContentTypeTable),
typeof (RemoveMasterContentTypeColumn),
typeof (RenameCmsTabTable),
typeof (RenameTabIdColumn),
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
typeof (UpdateCmsContentTypeTable),
typeof (UpdateCmsContentVersionTable),
typeof (UpdateCmsPropertyTypeGroupTable)
});
//this ensures its reset
PluginManager.Current = new PluginManager(false);
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
PluginManager.Current.AssembliesToScan = new[]
{
typeof (MigrationRunner).Assembly
};
Resolution.Freeze();
DatabaseSpecificSetUp();
@@ -43,7 +56,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
}
[Test]
public void Can_Upgrade_From_470_To_600()
public virtual void Can_Upgrade_From_470_To_600()
{
var configuredVersion = new Version("4.7.0");
var targetVersion = new Version("6.0.0");
@@ -53,13 +66,13 @@ namespace Umbraco.Tests.Migrations.Upgrades
//Create db schema and data from old Total.sql file for Sql Ce
string statements = GetDatabaseSpecificSqlScript();
// replace block comments by whitespace
statements = m_findComments.Replace(statements, " ");
statements = FindComments.Replace(statements, " ");
// execute all non-empty statements
foreach (string statement in statements.Split(";".ToCharArray()))
{
string rawStatement = statement.Trim();
string rawStatement = statement.Replace("GO", "").Trim();
if (rawStatement.Length > 0)
db.Execute(rawStatement);
db.Execute(new Sql(rawStatement));
}
//Setup the MigrationRunner
@@ -82,6 +95,8 @@ namespace Umbraco.Tests.Migrations.Upgrades
{
PluginManager.Current = null;
SyntaxConfig.SqlSyntaxProvider = null;
MigrationResolver.Reset();
Resolution.IsFrozen = false;
TestHelper.CleanContentDirectories();

Some files were not shown because too many files have changed in this diff Show More