Merge branch 'v8/dev' into v8/feature/284-auto-mapper

This commit is contained in:
Stephan
2019-04-02 12:03:05 +02:00
175 changed files with 3469 additions and 2852 deletions

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Compose
private static void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
{
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContent.ToInvariantString())))
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContentString)))
{
var relationService = Current.Services.RelationService;
const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias;
@@ -37,7 +37,7 @@ namespace Umbraco.Core.Compose
private static void MediaService_Moved(IMediaService sender, MoveEventArgs<IMedia> e)
{
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMedia.ToInvariantString())))
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMediaString)))
{
var relationService = Current.Services.RelationService;
const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias;

View File

@@ -98,7 +98,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions
: appPlugins.GetDirectories()
.SelectMany(x => x.GetDirectories("Lang"))
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 5)
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
//user defined langs that overwrite the default, these should not be used by plugin creators
@@ -106,7 +105,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
: configLangFolder
.GetFiles("*.user.xml", SearchOption.TopDirectoryOnly)
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 10)
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true));
return new LocalizedTextServiceFileSources(

View File

@@ -203,6 +203,28 @@ namespace Umbraco.Core
composition.RegisterUnique(_ => registrar);
}
/// <summary>
/// Sets the database server messenger options.
/// </summary>
/// <param name="composition">The composition.</param>
/// <param name="factory">A function creating the options.</param>
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
public static void SetDatabaseServerMessengerOptions(this Composition composition, Func<IFactory, DatabaseServerMessengerOptions> factory)
{
composition.RegisterUnique(factory);
}
/// <summary>
/// Sets the database server messenger options.
/// </summary>
/// <param name="composition">The composition.</param>
/// <param name="options">Options.</param>
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
public static void SetDatabaseServerMessengerOptions(this Composition composition, DatabaseServerMessengerOptions options)
{
composition.RegisterUnique(_ => options);
}
/// <summary>
/// Sets the short string helper.
/// </summary>

View File

@@ -93,7 +93,6 @@ namespace Umbraco.Core
/// </summary>
public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer";
/// <summary>
/// Debug specific web.config AppSetting keys for Umbraco
/// </summary>

View File

@@ -145,11 +145,11 @@
public const string PartialViewMacros = "partialViewMacros";
public const string LogViewer = "logViewer";
public const string LogViewer = "logViewer";
public static class Groups
{
public const string Settings = "settingsGroup";
public const string Settings = "settingsGroup";
public const string Templating = "templatingGroup";

View File

@@ -92,10 +92,10 @@ namespace Umbraco.Core
/// </summary>
public const string Extension = "umbracoExtension";
/// <summary>
/// The default height/width of an image file if the size can't be determined from the metadata
/// </summary>
public const int DefaultSize = 200;
/// <summary>
/// The default height/width of an image file if the size can't be determined from the metadata
/// </summary>
public const int DefaultSize = 200;
}
/// <summary>
@@ -209,71 +209,71 @@ namespace Umbraco.Core
public static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
{
return new Dictionary<string, PropertyType>
{
{
Comments,
new PropertyType(PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext, true, Comments)
{
Comments,
new PropertyType(PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext, true, Comments)
{
Name = CommentsLabel
}
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsApproved)
{
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsLockedOut)
{
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
Name = CommentsLabel
}
};
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsApproved)
{
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsLockedOut)
{
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
}
};
}
}

View File

@@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{
public static class Icons
{
/// <summary>
/// System contenttype icon
/// </summary>
@@ -42,12 +34,10 @@ namespace Umbraco.Core
/// </summary>
public const string MemberType = "icon-users";
/// <summary>
/// System member icon
/// </summary>
public const string Template = "icon-layout";
}
}
}

View File

@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{

View File

@@ -123,7 +123,6 @@ namespace Umbraco.Core
public static readonly Guid Template = new Guid(Strings.Template);
public static readonly Guid ContentItem = new Guid(Strings.ContentItem);
}
}
}

View File

@@ -3,7 +3,7 @@
public static partial class Constants
{
/// <summary>
/// Defines the constants used for the Umbraco package repository
/// Defines the constants used for the Umbraco package repository
/// </summary>
public static class PackageRepository
{

View File

@@ -34,7 +34,6 @@ namespace Umbraco.Core
/// </summary>
public const string ContentPicker = "Umbraco.ContentPicker";
/// <summary>
/// DateTime.
/// </summary>

View File

@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{
@@ -22,7 +19,6 @@ namespace Umbraco.Core
public const string PreviewCookieName = "UMB_PREVIEW";
public const string InstallerCookieName = "umb_installId";
}
}
}

View File

@@ -7,6 +7,7 @@ using System.Web;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPoco.Expressions;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
@@ -52,8 +53,8 @@ namespace Umbraco.Core
return ContentStatus.Unpublished;
}
#endregion
/// <summary>
@@ -134,9 +135,14 @@ namespace Umbraco.Core
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
/// <remarks>This really is for FileUpload fields only, and should be obsoleted. For anything else,
/// you need to store the file by yourself using Store and then figure out
/// how to deal with auto-fill properties (if any) and thumbnails (if any) by yourself.</remarks>
public static void SetValue(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, HttpPostedFileBase postedFile, string culture = null, string segment = null)
{
content.SetValue(contentTypeBaseServiceProvider, propertyTypeAlias, postedFile.FileName, postedFile.InputStream, culture, segment);
}
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
public static void SetValue(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null)
{
if (filename == null || filestream == null) return;

View File

@@ -151,22 +151,22 @@ namespace Umbraco.Core.Models
internal static bool HasContentRootAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasContentBinAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContent.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContentString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMedia.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMediaString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService)
@@ -327,7 +327,7 @@ namespace Umbraco.Core.Models
? entityService.GetAllPaths(objectType, asn).ToDictionary(x => x.Id, x => x.Path)
: new Dictionary<int, string>();
paths[Constants.System.Root] = Constants.System.Root.ToString(); // entityService does not get that one
paths[Constants.System.Root] = Constants.System.RootString; // entityService does not get that one
var binPath = GetBinPath(objectType);

View File

@@ -69,7 +69,7 @@ namespace Umbraco.Core
public const string Tag = /*TableNamePrefix*/ "cms" + "Tags";
public const string TagRelationship = /*TableNamePrefix*/ "cms" + "TagRelationship";
public const string KeyValue = TableNamePrefix + "KeyValue";
public const string AuditEntry = TableNamePrefix + "Audit";

View File

@@ -292,7 +292,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (psql.Arguments[i] is string s && s == "[[[ISOCODE]]]")
{
psql.Arguments[i] = ordering.Culture;
break;
}
}
}

View File

@@ -61,7 +61,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// move to parent (or -1), update path, save
moving.ParentId = parentId;
var movingPath = moving.Path + ","; // save before changing
moving.Path = (container == null ? Constants.System.Root.ToString() : container.Path) + "," + moving.Id;
moving.Path = (container == null ? Constants.System.RootString : container.Path) + "," + moving.Id;
moving.Level = container == null ? 1 : container.Level + 1;
Save(moving);

View File

@@ -232,7 +232,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
.OrderByDescending<ContentVersionDto>(x => x.Current)
.AndByDescending<ContentVersionDto>(x => x.VersionDate);
return MapDtosToContent(Database.Fetch<DocumentDto>(sql), true, true);
return MapDtosToContent(Database.Fetch<DocumentDto>(sql), true, true).Skip(skip).Take(take);
}
public override IContent GetVersion(int versionId)
@@ -982,8 +982,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// invariant: left join will yield NULL and we must use pcv to determine published
// variant: left join may yield NULL or something, and that determines published
var joins = Sql()
.InnerJoin<ContentTypeDto>("ctype").On<ContentDto, ContentTypeDto>((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype");
.InnerJoin<ContentTypeDto>("ctype").On<ContentDto, ContentTypeDto>((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype")
// left join on optional culture variation
//the magic "[[[ISOCODE]]]" parameter value will be replaced in ContentRepositoryBase.GetPage() by the actual ISO code
.LeftJoin<ContentVersionCultureVariationDto>(nested =>
nested.InnerJoin<LanguageDto>("langp").On<ContentVersionCultureVariationDto, LanguageDto>((ccv, lang) => ccv.LanguageId == lang.Id && lang.IsoCode == "[[[ISOCODE]]]", "ccvp", "langp"), "ccvp")
.On<ContentVersionDto, ContentVersionCultureVariationDto>((version, ccv) => version.Id == ccv.VersionId, aliasLeft: "pcv", aliasRight: "ccvp");
sql = InsertJoins(sql, joins);
@@ -993,7 +999,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// when invariant, ie 'variations' does not have the culture flag (value 1), use the global 'published' flag on pcv.id,
// otherwise check if there's a version culture variation for the lang, via ccv.id
", (CASE WHEN (ctype.variations & 1) = 0 THEN (CASE WHEN pcv.id IS NULL THEN 0 ELSE 1 END) ELSE (CASE WHEN ccv.id IS NULL THEN 0 ELSE 1 END) END) AS ordering "); // trailing space is important!
", (CASE WHEN (ctype.variations & 1) = 0 THEN (CASE WHEN pcv.id IS NULL THEN 0 ELSE 1 END) ELSE (CASE WHEN ccvp.id IS NULL THEN 0 ELSE 1 END) END) AS ordering "); // trailing space is important!
sql = Sql(sqlText, sql.Arguments);

View File

@@ -2,39 +2,61 @@
namespace Umbraco.Core.Scoping
{
// base class for an object that will be enlisted in scope context, if any. it
// must be used in a 'using' block, and if not scoped, released when disposed,
// else when scope context runs enlisted actions
/// <summary>
/// Provides a base class for scope contextual objects.
/// </summary>
/// <remarks>
/// <para>A scope contextual object is enlisted in the current scope context,
/// if any, and released when the context exists. It must be used in a 'using'
/// block, and will be released when disposed, if not part of a scope.</para>
/// </remarks>
public abstract class ScopeContextualBase : IDisposable
{
private bool _using, _scoped;
private bool _scoped;
/// <summary>
/// Gets a contextual object.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="scopeProvider">A scope provider.</param>
/// <param name="key">A context key for the object.</param>
/// <param name="ctor">A function producing the contextual object.</param>
/// <returns>The contextual object.</returns>
/// <remarks>
/// <para></para>
/// </remarks>
public static T Get<T>(IScopeProvider scopeProvider, string key, Func<bool, T> ctor)
where T : ScopeContextualBase
{
// no scope context = create a non-scoped object
var scopeContext = scopeProvider.Context;
if (scopeContext == null)
return ctor(false);
// create & enlist the scoped object
var w = scopeContext.Enlist("ScopeContextualBase_" + key,
() => ctor(true),
(completed, item) => { item.Release(completed); });
if (w._using) throw new InvalidOperationException("panic: used.");
w._using = true;
w._scoped = true;
return w;
}
/// <inheritdoc />
/// <remarks>
/// <para>If not scoped, then this releases the contextual object.</para>
/// </remarks>
public void Dispose()
{
_using = false;
if (_scoped == false)
Release(true);
}
/// <summary>
/// Releases the contextual object.
/// </summary>
/// <param name="completed">A value indicating whether the scoped operation completed.</param>
public abstract void Release(bool completed);
}
}

View File

@@ -533,7 +533,7 @@ namespace Umbraco.Core.Services.Implement
//null check otherwise we get exceptions
if (content.Path.IsNullOrWhiteSpace()) return Enumerable.Empty<IContent>();
var rootId = Constants.System.Root.ToInvariantString();
var rootId = Constants.System.RootString;
var ids = content.Path.Split(',')
.Where(x => x != rootId && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
if (ids.Any() == false)
@@ -1922,7 +1922,7 @@ namespace Umbraco.Core.Services.Implement
// if uow is not immediate, content.Path will be updated only when the UOW commits,
// and because we want it now, we have to calculate it by ourselves
//paths[content.Id] = content.Path;
paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : "-1") : parent.Path) + "," + content.Id;
paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : Constants.System.RootString) : parent.Path) + "," + content.Id;
const int pageSize = 500;
var page = 0;

View File

@@ -184,8 +184,12 @@ namespace Umbraco.Core.Services.Implement
//now load in supplementary
var found = _supplementFileSources.Where(x =>
{
var fileName = Path.GetFileName(x.File.FullName);
return fileName.InvariantStartsWith(culture.Name) && fileName.InvariantEndsWith(".xml");
var extension = Path.GetExtension(x.File.FullName);
var fileCultureName = Path.GetFileNameWithoutExtension(x.File.FullName).Replace("_", "-").Replace(".user", "");
return extension.InvariantEquals(".xml") && (
fileCultureName.InvariantEquals(culture.Name)
|| fileCultureName.InvariantEquals(culture.TwoLetterISOLanguageName)
);
});
foreach (var supplementaryFile in found)
@@ -203,7 +207,7 @@ namespace Umbraco.Core.Services.Implement
continue;
}
if (xChildDoc.Root == null) continue;
if (xChildDoc.Root == null || xChildDoc.Root.Name != "language") continue;
foreach (var xArea in xChildDoc.Root.Elements("area")
.Where(x => ((string)x.Attribute("alias")).IsNullOrWhiteSpace() == false))
{

View File

@@ -995,7 +995,7 @@ namespace Umbraco.Core.Services.Implement
// if uow is not immediate, content.Path will be updated only when the UOW commits,
// and because we want it now, we have to calculate it by ourselves
//paths[media.Id] = media.Path;
paths[media.Id] = (parent == null ? (parentId == Constants.System.RecycleBinMedia ? "-1,-21" : "-1") : parent.Path) + "," + media.Id;
paths[media.Id] = (parent == null ? (parentId == Constants.System.RecycleBinMedia ? "-1,-21" : Constants.System.RootString) : parent.Path) + "," + media.Id;
const int pageSize = 500;
var page = 0;

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Core
internal static Dictionary<string, UdiType> GetTypes()
{
return new Dictionary<string,UdiType>
return new Dictionary<string, UdiType>
{
{ Unknown, UdiType.Unknown },

View File

@@ -23,21 +23,21 @@ namespace Umbraco.Core
/// <returns></returns>
/// <remarks>
/// There are some special routes we need to check to properly determine this:
///
///
/// If any route has an extension in the path like .aspx = back office
///
///
/// These are def back office:
/// /Umbraco/BackOffice = back office
/// /Umbraco/Preview = back office
/// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end
/// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice
/// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute.
///
///
/// These are def front-end:
/// /Umbraco/Surface = front-end
/// /Umbraco/Api = front-end
/// But if we've got this far we'll just have to assume it's front-end anyways.
///
///
/// </remarks>
internal static bool IsBackOfficeRequest(this Uri url, string applicationPath, IGlobalSettings globalSettings)
{
@@ -152,9 +152,9 @@ namespace Umbraco.Core
var toInclude = new[] {".aspx", ".ashx", ".asmx", ".axd", ".svc"};
return toInclude.Any(ext.InvariantEquals) == false;
}
catch (ArgumentException ex)
catch (ArgumentException)
{
Current.Logger.Error(typeof(UriExtensions), ex, "Failed to determine if request was client side");
Current.Logger.Debug(typeof(UriExtensions), "Failed to determine if request was client side (invalid chars in path \"{Path}\"?)", url.LocalPath);
return false;
}
}