Merge remote-tracking branch 'origin/v9/dev' into v9/bugfix/external-login-changes
# Conflicts: # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
This commit is contained in:
@@ -46,6 +46,7 @@ namespace JsonSchema
|
||||
public UnattendedSettings Unattended { get; set; }
|
||||
public RichTextEditorSettings RichTextEditor { get; set; }
|
||||
public RuntimeMinificationSettings RuntimeMinification { get; set; }
|
||||
public BasicAuthSettings BasicAuth { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.4.4" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.5.2" />
|
||||
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
|
||||
<PackageReference Include="Umbraco.Forms.Core" Version="9.0.0-preview20210624.66481" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -11,9 +11,10 @@ namespace Umbraco.Extensions
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a published snapshot service.</param>
|
||||
public static void SetPublishedSnapshotService(this IUmbracoBuilder builder, Func<IServiceProvider, IPublishedSnapshotService> factory)
|
||||
public static IUmbracoBuilder SetPublishedSnapshotService(this IUmbracoBuilder builder, Func<IServiceProvider, IPublishedSnapshotService> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -21,10 +22,11 @@ namespace Umbraco.Extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the published snapshot service.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetPublishedSnapshotService<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetPublishedSnapshotService<T>(this IUmbracoBuilder builder)
|
||||
where T : class, IPublishedSnapshotService
|
||||
{
|
||||
builder.Services.AddUnique<IPublishedSnapshotService, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,9 +34,10 @@ namespace Umbraco.Extensions
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="service">A published snapshot service.</param>
|
||||
public static void SetPublishedSnapshotService(this IUmbracoBuilder builder, IPublishedSnapshotService service)
|
||||
public static IUmbracoBuilder SetPublishedSnapshotService(this IUmbracoBuilder builder, IPublishedSnapshotService service)
|
||||
{
|
||||
builder.Services.AddUnique(service);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ namespace Umbraco.Cms.Core.Composing
|
||||
"HtmlDiff,",
|
||||
"ICSharpCode.",
|
||||
"Iesi.Collections,", // used by NHibernate
|
||||
"JetBrains.Annotations,",
|
||||
"LightInject.", // DI
|
||||
"LightInject,",
|
||||
"Lucene.",
|
||||
|
||||
@@ -17,48 +17,57 @@ namespace Umbraco.Cms.Core.Configuration
|
||||
public string ProviderName { get; }
|
||||
public string Name { get; }
|
||||
|
||||
private string ParseProvider(string connectionString)
|
||||
private static bool IsSqlCe(DbConnectionStringBuilder builder) => (builder.TryGetValue("Data Source", out var ds)
|
||||
|| builder.TryGetValue("DataSource", out ds)) &&
|
||||
ds is string dataSource &&
|
||||
dataSource.EndsWith(".sdf");
|
||||
|
||||
private static bool IsSqlServer(DbConnectionStringBuilder builder) =>
|
||||
!string.IsNullOrEmpty(GetServer(builder)) &&
|
||||
((builder.TryGetValue("Database", out var db) && db is string database &&
|
||||
!string.IsNullOrEmpty(database)) ||
|
||||
(builder.TryGetValue("AttachDbFileName", out var a) && a is string attachDbFileName &&
|
||||
!string.IsNullOrEmpty(attachDbFileName)) ||
|
||||
(builder.TryGetValue("Initial Catalog", out var i) && i is string initialCatalog &&
|
||||
!string.IsNullOrEmpty(initialCatalog)));
|
||||
|
||||
private static string GetServer(DbConnectionStringBuilder builder)
|
||||
{
|
||||
if(builder.TryGetValue("Server", out var s) && s is string server)
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
if ((builder.TryGetValue("Data Source", out var ds)
|
||||
|| builder.TryGetValue("DataSource", out ds)) && ds is string dataSource)
|
||||
{
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private static string ParseProvider(string connectionString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var builder = new DbConnectionStringBuilder
|
||||
var builder = new DbConnectionStringBuilder {ConnectionString = connectionString};
|
||||
if (IsSqlCe(builder))
|
||||
{
|
||||
ConnectionString = connectionString
|
||||
};
|
||||
|
||||
if (
|
||||
(builder.TryGetValue("Data Source", out var ds)
|
||||
|| builder.TryGetValue("DataSource", out ds)) && ds is string dataSource)
|
||||
{
|
||||
if (dataSource.EndsWith(".sdf"))
|
||||
{
|
||||
return Umbraco.Cms.Core.Constants.DbProviderNames.SqlCe;
|
||||
}
|
||||
return Constants.DbProviderNames.SqlCe;
|
||||
}
|
||||
|
||||
|
||||
if (builder.TryGetValue("Server", out var s) && s is string server && !string.IsNullOrEmpty(server))
|
||||
if (IsSqlServer(builder))
|
||||
{
|
||||
if (builder.TryGetValue("Database", out var db) && db is string database && !string.IsNullOrEmpty(database))
|
||||
{
|
||||
return Umbraco.Cms.Core.Constants.DbProviderNames.SqlServer;
|
||||
}
|
||||
|
||||
if (builder.TryGetValue("AttachDbFileName", out var a) && a is string attachDbFileName && !string.IsNullOrEmpty(attachDbFileName))
|
||||
{
|
||||
return Umbraco.Cms.Core.Constants.DbProviderNames.SqlServer;
|
||||
}
|
||||
|
||||
if (builder.TryGetValue("Initial Catalog", out var i) && i is string initialCatalog && !string.IsNullOrEmpty(initialCatalog))
|
||||
{
|
||||
return Umbraco.Cms.Core.Constants.DbProviderNames.SqlServer;
|
||||
}
|
||||
return Constants.DbProviderNames.SqlServer;
|
||||
}
|
||||
|
||||
throw new ArgumentException("Cannot determine provider name from connection string", nameof(connectionString));
|
||||
throw new ArgumentException("Cannot determine provider name from connection string",
|
||||
nameof(connectionString));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
namespace Umbraco.Core.Dashboards
|
||||
namespace Umbraco.Cms.Core.Configuration
|
||||
{
|
||||
public class ContentDashboardSettings
|
||||
{
|
||||
private const string DefaultContentDashboardPath = "cms";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content dashboard should be available to all users.
|
||||
/// </summary>
|
||||
|
||||
27
src/Umbraco.Core/Configuration/Models/BasicAuthSettings.cs
Normal file
27
src/Umbraco.Core/Configuration/Models/BasicAuthSettings.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Net;
|
||||
|
||||
namespace Umbraco.Cms.Core.Configuration.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Typed configuration options for basic authentication settings.
|
||||
/// </summary>
|
||||
[UmbracoOptions(Constants.Configuration.ConfigBasicAuth)]
|
||||
public class BasicAuthSettings
|
||||
{
|
||||
private const bool StaticEnabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to keep the user logged in.
|
||||
/// </summary>
|
||||
[DefaultValue(StaticEnabled)]
|
||||
public bool Enabled { get; set; } = StaticEnabled;
|
||||
|
||||
|
||||
public string[] AllowedIPs { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
@@ -30,5 +30,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
/// </summary>
|
||||
[DefaultValue(StaticSqlPageSize)]
|
||||
public int SqlPageSize { get; set; } = StaticSqlPageSize;
|
||||
|
||||
public bool UnPublishedContentCompression { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
internal const bool StaticHideDisabledUsersInBackOffice = false;
|
||||
internal const bool StaticAllowPasswordReset = true;
|
||||
internal const string StaticAuthCookieName = "UMB_UCONTEXT";
|
||||
internal const string StaticAllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+\\";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to keep the user logged in.
|
||||
@@ -50,6 +51,12 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
/// </summary>
|
||||
public bool UsernameIsEmail { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the set of allowed characters for a username
|
||||
/// </summary>
|
||||
[DefaultValue(StaticAllowedUserNameCharacters)]
|
||||
public string AllowedUserNameCharacters { get; set; } = StaticAllowedUserNameCharacters;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value for the user password settings.
|
||||
/// </summary>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
public const string ConfigRuntimeMinification = ConfigPrefix + "RuntimeMinification";
|
||||
public const string ConfigRuntimeMinificationVersion = ConfigRuntimeMinification + ":Version";
|
||||
public const string ConfigSecurity = ConfigPrefix + "Security";
|
||||
public const string ConfigBasicAuth = ConfigPrefix + "BasicAuth";
|
||||
public const string ConfigTours = ConfigPrefix + "Tours";
|
||||
public const string ConfigTypeFinder = ConfigPrefix + "TypeFinder";
|
||||
public const string ConfigWebRouting = ConfigPrefix + "WebRouting";
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
.AddUmbracoOptions<UmbracoPluginSettings>()
|
||||
.AddUmbracoOptions<UnattendedSettings>()
|
||||
.AddUmbracoOptions<RichTextEditorSettings>()
|
||||
.AddUmbracoOptions<BasicAuthSettings>()
|
||||
.AddUmbracoOptions<RuntimeMinificationSettings>();
|
||||
|
||||
return builder;
|
||||
|
||||
27
src/Umbraco.Core/Models/ContentEditing/ContentTypesByKeys.cs
Normal file
27
src/Umbraco.Core/Models/ContentEditing/ContentTypesByKeys.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models.ContentEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// A model for retrieving multiple content types based on their keys.
|
||||
/// </summary>
|
||||
[DataContract(Name = "contentTypes", Namespace = "")]
|
||||
public class ContentTypesByKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// ID of the parent of the content type.
|
||||
/// </summary>
|
||||
[DataMember(Name = "parentId")]
|
||||
[Required]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The id of every content type to get.
|
||||
/// </summary>
|
||||
[DataMember(Name = "contentTypeKeys")]
|
||||
[Required]
|
||||
public Guid[] ContentTypeKeys { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,12 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
///
|
||||
/// </remarks>
|
||||
public interface IPropertyCacheCompression
|
||||
{
|
||||
bool IsCompressed(IReadOnlyContentBase content, string propertyTypeAlias);
|
||||
{/// <summary>
|
||||
/// Whether a property on the content is/should be compressed
|
||||
/// </summary>
|
||||
/// <param name="content">The content</param>
|
||||
/// <param name="propertyTypeAlias">The property to compress or not</param>
|
||||
/// <param name="published">Whether this content is the published version</param>
|
||||
bool IsCompressed(IReadOnlyContentBase content, string propertyTypeAlias, bool published);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
public interface IPropertyCacheCompressionOptions
|
||||
{
|
||||
bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor);
|
||||
/// <summary>
|
||||
/// Whether a property on the content is/should be compressed
|
||||
/// </summary>
|
||||
/// <param name="content">The content</param>
|
||||
/// <param name="propertyType">The property to compress or not</param>
|
||||
/// <param name="dataEditor">The datatype of the property to compress or not</param>
|
||||
/// <param name="published">Whether this content is the published version</param>
|
||||
bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor, bool published);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,14 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
|
||||
public bool TryGetMediaPath(string propertyEditorAlias, object value, out string mediaPath)
|
||||
{
|
||||
// We can't get a media path from a null value
|
||||
// The value will be null when uploading a brand new image, since we try to get the "old path" which doesn't exist yet.
|
||||
if (value is null)
|
||||
{
|
||||
mediaPath = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach(IMediaUrlGenerator generator in this)
|
||||
{
|
||||
if (generator.TryGetMediaPath(propertyEditorAlias, value, out var mp))
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
/// </summary>
|
||||
public sealed class NoopPropertyCacheCompressionOptions : IPropertyCacheCompressionOptions
|
||||
{
|
||||
public bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor) => false;
|
||||
public bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor, bool published) => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -16,13 +16,13 @@ namespace Umbraco.Core.PropertyEditors
|
||||
private readonly IPropertyCacheCompressionOptions _compressionOptions;
|
||||
private readonly IReadOnlyDictionary<int, IContentTypeComposition> _contentTypes;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly ConcurrentDictionary<(int contentTypeId, string propertyAlias), bool> _isCompressedCache;
|
||||
private readonly ConcurrentDictionary<(int contentTypeId, string propertyAlias, bool published), bool> _isCompressedCache;
|
||||
|
||||
public PropertyCacheCompression(
|
||||
IPropertyCacheCompressionOptions compressionOptions,
|
||||
IReadOnlyDictionary<int, IContentTypeComposition> contentTypes,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
ConcurrentDictionary<(int, string), bool> compressedStoragePropertyEditorCache)
|
||||
ConcurrentDictionary<(int, string, bool), bool> compressedStoragePropertyEditorCache)
|
||||
{
|
||||
_compressionOptions = compressionOptions;
|
||||
_contentTypes = contentTypes ?? throw new System.ArgumentNullException(nameof(contentTypes));
|
||||
@@ -30,9 +30,9 @@ namespace Umbraco.Core.PropertyEditors
|
||||
_isCompressedCache = compressedStoragePropertyEditorCache;
|
||||
}
|
||||
|
||||
public bool IsCompressed(IReadOnlyContentBase content, string alias)
|
||||
public bool IsCompressed(IReadOnlyContentBase content, string alias, bool published)
|
||||
{
|
||||
var compressedStorage = _isCompressedCache.GetOrAdd((content.ContentTypeId, alias), x =>
|
||||
var compressedStorage = _isCompressedCache.GetOrAdd((content.ContentTypeId, alias, published), x =>
|
||||
{
|
||||
if (!_contentTypes.TryGetValue(x.contentTypeId, out var ct))
|
||||
return false;
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
if (!_propertyEditors.TryGet(propertyType.PropertyEditorAlias, out var propertyEditor))
|
||||
return false;
|
||||
|
||||
return _compressionOptions.IsCompressed(content, propertyType, propertyEditor);
|
||||
return _compressionOptions.IsCompressed(content, propertyType, propertyEditor, published);
|
||||
});
|
||||
|
||||
return compressedStorage;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Compress large, non published text properties
|
||||
/// </summary>
|
||||
public class UnPublishedContentPropertyCacheCompressionOptions : IPropertyCacheCompressionOptions
|
||||
{
|
||||
public bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor, bool published)
|
||||
{
|
||||
if (!published && propertyType.SupportsPublishing && propertyType.ValueStorageType == ValueStorageType.Ntext)
|
||||
{
|
||||
//Only compress non published content that supports publishing and the property is text
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/Umbraco.Core/Services/IBasicAuthService.cs
Normal file
10
src/Umbraco.Core/Services/IBasicAuthService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Net;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public interface IBasicAuthService
|
||||
{
|
||||
bool IsBasicAuthEnabled();
|
||||
bool IsIpAllowListed(IPAddress clientIpAddress);
|
||||
}
|
||||
}
|
||||
@@ -34,17 +34,6 @@ namespace Umbraco.Extensions
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, string[] tokens)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, ConvertToDictionaryVars(tokens));
|
||||
|
||||
/// <summary>
|
||||
/// Localize using the current thread culture
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="tokens"></param>
|
||||
/// <returns></returns>
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, IDictionary<string, string> tokens = null)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, tokens);
|
||||
|
||||
/// <summary>
|
||||
/// Localize a key without any variables
|
||||
/// </summary>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
|
||||
@@ -59,4 +59,8 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="EmbeddedResources\**\*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ContentEditing" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -30,11 +30,6 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SecurityCodeScan">
|
||||
<Version>3.5.4</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Umbraco.Code" Version="1.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -2,12 +2,8 @@ using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Services.Changes;
|
||||
using Umbraco.Cms.Core.Sync;
|
||||
using Umbraco.Cms.Infrastructure.Search;
|
||||
using Umbraco.Cms.Infrastructure.Sync;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -40,49 +36,67 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the server registrar.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetServerRegistrar<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetServerRegistrar<T>(this IUmbracoBuilder builder)
|
||||
where T : class, IServerRoleAccessor
|
||||
=> builder.Services.AddUnique<IServerRoleAccessor, T>();
|
||||
{
|
||||
builder.Services.AddUnique<IServerRoleAccessor, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the server registrar.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a server registrar.</param>
|
||||
public static void SetServerRegistrar(this IUmbracoBuilder builder, Func<IServiceProvider, IServerRoleAccessor> factory)
|
||||
=> builder.Services.AddUnique(factory);
|
||||
public static IUmbracoBuilder SetServerRegistrar(this IUmbracoBuilder builder, Func<IServiceProvider, IServerRoleAccessor> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the server registrar.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="registrar">A server registrar.</param>
|
||||
public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor registrar)
|
||||
=> builder.Services.AddUnique(registrar);
|
||||
public static IUmbracoBuilder SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor registrar)
|
||||
{
|
||||
builder.Services.AddUnique(registrar);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the server messenger.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the server registrar.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetServerMessenger<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetServerMessenger<T>(this IUmbracoBuilder builder)
|
||||
where T : class, IServerMessenger
|
||||
=> builder.Services.AddUnique<IServerMessenger, T>();
|
||||
{
|
||||
builder.Services.AddUnique<IServerMessenger, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the server messenger.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a server messenger.</param>
|
||||
public static void SetServerMessenger(this IUmbracoBuilder builder, Func<IServiceProvider, IServerMessenger> factory)
|
||||
=> builder.Services.AddUnique(factory);
|
||||
public static IUmbracoBuilder SetServerMessenger(this IUmbracoBuilder builder, Func<IServiceProvider, IServerMessenger> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the server messenger.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="registrar">A server messenger.</param>
|
||||
public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar)
|
||||
=> builder.Services.AddUnique(registrar);
|
||||
public static IUmbracoBuilder SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar)
|
||||
{
|
||||
builder.Services.AddUnique(registrar);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
builder.Services.AddUnique<IDomainService, DomainService>();
|
||||
builder.Services.AddUnique<IAuditService, AuditService>();
|
||||
builder.Services.AddUnique<ICacheInstructionService, CacheInstructionService>();
|
||||
builder.Services.AddUnique<IBasicAuthService, BasicAuthService>();
|
||||
builder.Services.AddUnique<ITagService, TagService>();
|
||||
builder.Services.AddUnique<IContentService, ContentService>();
|
||||
builder.Services.AddUnique<IUserService, UserService>();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Dictionary;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
@@ -21,10 +20,11 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the factory.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetCultureDictionaryFactory<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetCultureDictionaryFactory<T>(this IUmbracoBuilder builder)
|
||||
where T : class, ICultureDictionaryFactory
|
||||
{
|
||||
builder.Services.AddUnique<ICultureDictionaryFactory, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,9 +32,10 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a culture dictionary factory.</param>
|
||||
public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func<IServiceProvider, ICultureDictionaryFactory> factory)
|
||||
public static IUmbracoBuilder SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func<IServiceProvider, ICultureDictionaryFactory> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,9 +43,10 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A factory.</param>
|
||||
public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory)
|
||||
public static IUmbracoBuilder SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,10 +54,11 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the factory.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetPublishedContentModelFactory<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetPublishedContentModelFactory<T>(this IUmbracoBuilder builder)
|
||||
where T : class, IPublishedModelFactory
|
||||
{
|
||||
builder.Services.AddUnique<IPublishedModelFactory, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -63,9 +66,10 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a published content model factory.</param>
|
||||
public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func<IServiceProvider, IPublishedModelFactory> factory)
|
||||
public static IUmbracoBuilder SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func<IServiceProvider, IPublishedModelFactory> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,9 +77,10 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A published content model factory.</param>
|
||||
public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory)
|
||||
public static IUmbracoBuilder SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,10 +88,11 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the short string helper.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetShortStringHelper<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetShortStringHelper<T>(this IUmbracoBuilder builder)
|
||||
where T : class, IShortStringHelper
|
||||
{
|
||||
builder.Services.AddUnique<IShortStringHelper, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,9 +100,10 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a short string helper.</param>
|
||||
public static void SetShortStringHelper(this IUmbracoBuilder builder, Func<IServiceProvider, IShortStringHelper> factory)
|
||||
public static IUmbracoBuilder SetShortStringHelper(this IUmbracoBuilder builder, Func<IServiceProvider, IShortStringHelper> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -104,9 +111,10 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">A builder.</param>
|
||||
/// <param name="helper">A short string helper.</param>
|
||||
public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper)
|
||||
public static IUmbracoBuilder SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper)
|
||||
{
|
||||
builder.Services.AddUnique(helper);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,19 +122,23 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">A builder.</param>
|
||||
/// <param name="filesystemFactory">Factory method to create an IFileSystem implementation used in the MediaFileManager</param>
|
||||
public static void SetMediaFileSystem(this IUmbracoBuilder builder,
|
||||
Func<IServiceProvider, IFileSystem> filesystemFactory) => builder.Services.AddUnique(
|
||||
provider =>
|
||||
{
|
||||
IFileSystem filesystem = filesystemFactory(provider);
|
||||
// We need to use the Filesystems to create a shadow wrapper,
|
||||
// because shadow wrapper requires the IsScoped delegate from the FileSystems.
|
||||
// This is used by the scope provider when taking control of the filesystems.
|
||||
FileSystems fileSystems = provider.GetRequiredService<FileSystems>();
|
||||
IFileSystem shadow = fileSystems.CreateShadowWrapper(filesystem, "media");
|
||||
public static IUmbracoBuilder SetMediaFileSystem(this IUmbracoBuilder builder,
|
||||
Func<IServiceProvider, IFileSystem> filesystemFactory)
|
||||
{
|
||||
builder.Services.AddUnique(
|
||||
provider =>
|
||||
{
|
||||
IFileSystem filesystem = filesystemFactory(provider);
|
||||
// We need to use the Filesystems to create a shadow wrapper,
|
||||
// because shadow wrapper requires the IsScoped delegate from the FileSystems.
|
||||
// This is used by the scope provider when taking control of the filesystems.
|
||||
FileSystems fileSystems = provider.GetRequiredService<FileSystems>();
|
||||
IFileSystem shadow = fileSystems.CreateShadowWrapper(filesystem, "media");
|
||||
|
||||
return provider.CreateInstance<MediaFileManager>(shadow);
|
||||
});
|
||||
return provider.CreateInstance<MediaFileManager>(shadow);
|
||||
});
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register FileSystems with a method to configure the <see cref="FileSystems"/>.
|
||||
@@ -135,7 +147,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// <param name="configure">Method that configures the <see cref="FileSystems"/>.</param>
|
||||
/// <exception cref="ArgumentNullException">Throws exception if <paramref name="configure"/> is null.</exception>
|
||||
/// <exception cref="InvalidOperationException">Throws exception if full path can't be resolved successfully.</exception>
|
||||
public static void ConfigureFileSystems(this IUmbracoBuilder builder,
|
||||
public static IUmbracoBuilder ConfigureFileSystems(this IUmbracoBuilder builder,
|
||||
Action<IServiceProvider, FileSystems> configure)
|
||||
{
|
||||
if (configure == null)
|
||||
@@ -150,6 +162,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
configure(provider, fileSystems);
|
||||
return fileSystems;
|
||||
});
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -157,10 +170,11 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the log viewer.</typeparam>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static void SetLogViewer<T>(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder SetLogViewer<T>(this IUmbracoBuilder builder)
|
||||
where T : class, ILogViewer
|
||||
{
|
||||
builder.Services.AddUnique<ILogViewer, T>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -168,19 +182,21 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
/// <param name="factory">A function creating a log viewer.</param>
|
||||
public static void SetLogViewer(this IUmbracoBuilder builder, Func<IServiceProvider, ILogViewer> factory)
|
||||
public static IUmbracoBuilder SetLogViewer(this IUmbracoBuilder builder, Func<IServiceProvider, ILogViewer> factory)
|
||||
{
|
||||
builder.Services.AddUnique(factory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the log viewer.
|
||||
/// </summary>
|
||||
/// <param name="builder">A builder.</param>
|
||||
/// <param name="helper">A log viewer.</param>
|
||||
public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer)
|
||||
/// <param name="viewer">A log viewer.</param>
|
||||
public static IUmbracoBuilder SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer)
|
||||
{
|
||||
builder.Services.AddUnique(viewer);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table
|
||||
public class CreateTableOfDtoBuilder : IExecutableBuilder
|
||||
{
|
||||
private readonly IMigrationContext _context;
|
||||
|
||||
// TODO: This doesn't do anything.
|
||||
private readonly DatabaseType[] _supportedDatabaseTypes;
|
||||
|
||||
public CreateTableOfDtoBuilder(IMigrationContext context, params DatabaseType[] supportedDatabaseTypes)
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade
|
||||
Merge()
|
||||
.To<AddCmsContentNuByteColumn>("{8DDDCD0B-D7D5-4C97-BD6A-6B38CA65752F}")
|
||||
.To<UpgradedIncludeIndexes>("{4695D0C9-0729-4976-985B-048D503665D8}")
|
||||
|
||||
.To<UpdateCmsPropertyGroupIdSeed>("{5C424554-A32D-4852-8ED1-A13508187901}")
|
||||
// to 9.0.0 RC
|
||||
.With()
|
||||
.To<MigrateLogViewerQueriesFromFileToDb>("{22D801BA-A1FF-4539-BFCC-2139B55594F8}")
|
||||
@@ -224,6 +224,14 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade
|
||||
.As("{5060F3D2-88BE-4D30-8755-CF51F28EAD12}");
|
||||
|
||||
// TO 9.0.0
|
||||
|
||||
|
||||
// This should be safe to execute again. We need it with a new name to ensure updates from all the following has executed this step.
|
||||
// - 8.15 RC - Current state: {4695D0C9-0729-4976-985B-048D503665D8}
|
||||
// - 8.15 Final - Current state: {5C424554-A32D-4852-8ED1-A13508187901}
|
||||
// - 9.0 RC1 - Current state: {5060F3D2-88BE-4D30-8755-CF51F28EAD12}
|
||||
To<UpdateCmsPropertyGroupIdSeed>("{622E5172-42E1-4662-AD80-9504AF5A4E53}");
|
||||
|
||||
To<ExternalLoginTableIndexesFixup>("{10F7BB61-C550-426B-830B-7F954F689CDF}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using NPoco;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0
|
||||
{
|
||||
@@ -14,12 +17,49 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0
|
||||
|
||||
protected override void Migrate()
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
|
||||
// allow null for the `data` field
|
||||
if (DatabaseType.IsSqlCe())
|
||||
{
|
||||
// SQLCE does not support altering NTEXT, so we have to jump through some hoops to do it
|
||||
// All column ordering must remain the same as what is defined in the DTO so we need to create a temp table,
|
||||
// drop orig and then re-create/copy.
|
||||
Create.Table<ContentNuDtoTemp>(withoutKeysAndIndexes: true).Do();
|
||||
Execute.Sql($"INSERT INTO [{TempTableName}] SELECT nodeId, published, data, rv FROM [{Constants.DatabaseSchema.Tables.NodeData}]").Do();
|
||||
Delete.Table(Constants.DatabaseSchema.Tables.NodeData).Do();
|
||||
Create.Table<ContentNuDto>().Do();
|
||||
Execute.Sql($"INSERT INTO [{Constants.DatabaseSchema.Tables.NodeData}] SELECT nodeId, published, data, rv, NULL FROM [{TempTableName}]").Do();
|
||||
}
|
||||
else
|
||||
{
|
||||
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
|
||||
}
|
||||
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
|
||||
AddColumnIfNotExists<ContentNuDto>(columns, "dataRaw");
|
||||
|
||||
// allow null
|
||||
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
|
||||
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
|
||||
}
|
||||
|
||||
private const string TempTableName = Constants.DatabaseSchema.TableNamePrefix + "cms" + "ContentNuTEMP";
|
||||
|
||||
[TableName(TempTableName)]
|
||||
[ExplicitColumns]
|
||||
private class ContentNuDtoTemp
|
||||
{
|
||||
[Column("nodeId")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[Column("published")]
|
||||
public bool Published { get; set; }
|
||||
|
||||
[Column("data")]
|
||||
[SpecialDbType(SpecialDbTypes.NTEXT)]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Data { get; set; }
|
||||
|
||||
[Column("rv")]
|
||||
public long Rv { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0
|
||||
{
|
||||
public class UpdateCmsPropertyGroupIdSeed : MigrationBase
|
||||
{
|
||||
public UpdateCmsPropertyGroupIdSeed(IMigrationContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Migrate()
|
||||
{
|
||||
if (DatabaseType.IsSqlCe())
|
||||
{
|
||||
Database.Execute(Sql("ALTER TABLE [cmsPropertyTypeGroup] ALTER COLUMN [id] IDENTITY (56,1)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a media item with local crops.
|
||||
|
||||
@@ -98,6 +98,13 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building
|
||||
sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder.Embedded\", \"{1}\")]\n", tabs, ApiVersion.Current.Version);
|
||||
}
|
||||
|
||||
// writes an attribute that specifies that an output may be null.
|
||||
// (useful for consuming projects with nullable reference types enabled)
|
||||
private static void WriteMaybeNullAttribute(StringBuilder sb, string tabs, bool isReturn = false)
|
||||
{
|
||||
sb.AppendFormat("{0}[{1}global::System.Diagnostics.CodeAnalysis.MaybeNull]\n", tabs, isReturn ? "return: " : "");
|
||||
}
|
||||
|
||||
private void WriteContentType(StringBuilder sb, TypeModel type)
|
||||
{
|
||||
string sep;
|
||||
@@ -185,9 +192,11 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building
|
||||
sb.AppendFormat("\t\tpublic new const PublishedItemType ModelItemType = PublishedItemType.{0};\n",
|
||||
itemType);
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
WriteMaybeNullAttribute(sb, "\t\t", true);
|
||||
sb.Append("\t\tpublic new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor)\n");
|
||||
sb.Append("\t\t\t=> PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias);\n");
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
WriteMaybeNullAttribute(sb, "\t\t", true);
|
||||
sb.AppendFormat("\t\tpublic static IPublishedPropertyType GetModelPropertyType<TValue>(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression<Func<{0}, TValue>> selector)\n",
|
||||
type.ClrName);
|
||||
sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);\n");
|
||||
@@ -305,6 +314,8 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building
|
||||
}
|
||||
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
if (!property.ModelClrType.IsValueType)
|
||||
WriteMaybeNullAttribute(sb, "\t\t");
|
||||
sb.AppendFormat("\t\t[ImplementPropertyType(\"{0}\")]\n", property.Alias);
|
||||
|
||||
if (mixinStatic)
|
||||
@@ -349,6 +360,8 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building
|
||||
sb.AppendFormat("\t\t/// <summary>Static getter for {0}</summary>\n", XmlCommentString(property.Name));
|
||||
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
if (!property.ModelClrType.IsValueType)
|
||||
WriteMaybeNullAttribute(sb, "\t\t", true);
|
||||
sb.Append("\t\tpublic static ");
|
||||
WriteClrType(sb, property.ClrTypeName);
|
||||
sb.AppendFormat(" {0}(I{1} that, IPublishedValueFallback publishedValueFallback) => that.Value",
|
||||
@@ -404,6 +417,9 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building
|
||||
if (!string.IsNullOrWhiteSpace(property.Name))
|
||||
sb.AppendFormat("\t\t/// <summary>{0}</summary>\n", XmlCommentString(property.Name));
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
if (!property.ModelClrType.IsValueType)
|
||||
WriteMaybeNullAttribute(sb, "\t\t");
|
||||
|
||||
sb.Append("\t\t");
|
||||
WriteClrType(sb, property.ClrTypeName);
|
||||
sb.AppendFormat(" {0} {{ get; }}\n",
|
||||
|
||||
@@ -13,10 +13,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
|
||||
public int BulkInsertRecords<T>(IUmbracoDatabase database, IEnumerable<T> records)
|
||||
{
|
||||
var recordsA = records.ToArray();
|
||||
if (recordsA.Length == 0) return 0;
|
||||
if (!records.Any()) return 0;
|
||||
|
||||
return BulkInsertRecordsWithCommands(database, recordsA);
|
||||
return BulkInsertRecordsWithCommands(database, records.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos
|
||||
internal class PropertyTypeGroupDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 12)]
|
||||
[PrimaryKeyColumn(IdentitySeed = 56)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("contenttypeNodeId")]
|
||||
|
||||
@@ -41,9 +41,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
_tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
|
||||
if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.Type);
|
||||
|
||||
// only real columns, exclude result columns
|
||||
// only real columns, exclude result/computed columns
|
||||
// Like NPoco does: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L59
|
||||
_readerColumns = pd.Columns
|
||||
.Where(x => x.Value.ResultColumn == false)
|
||||
.Where(x => x.Value.ResultColumn == false && x.Value.ComputedColumn == false)
|
||||
.Select(x => x.Value)
|
||||
.ToArray();
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
/// <returns>The number of records that were inserted.</returns>
|
||||
private int BulkInsertRecordsSqlServer<T>(IUmbracoDatabase database, PocoData pocoData, IEnumerable<T> records)
|
||||
{
|
||||
// TODO: The main reason this exists is because the NPoco InsertBulk method doesn't return the number of items.
|
||||
// It is worth investigating the performance of this vs NPoco's because we use a custom BulkDataReader
|
||||
// which in theory should be more efficient than NPocos way of building up an in-memory DataTable.
|
||||
|
||||
// create command against the original database.Connection
|
||||
using (var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty))
|
||||
{
|
||||
@@ -50,7 +54,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
var syntax = database.SqlContext.SqlSyntax as SqlServerSyntaxProvider;
|
||||
if (syntax == null) throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider.");
|
||||
|
||||
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName })
|
||||
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction)
|
||||
{
|
||||
BulkCopyTimeout = 0, // 0 = no bulk copy timeout. If a timeout occurs it will be an connection/command timeout.
|
||||
DestinationTableName = tableName,
|
||||
// be consistent with NPoco: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L50
|
||||
BatchSize = 4096
|
||||
})
|
||||
using (var bulkReader = new PocoDataDataReader<T, SqlServerSyntaxProvider>(records, pocoData, syntax))
|
||||
{
|
||||
//we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
public class BasicAuthService : IBasicAuthService
|
||||
{
|
||||
private BasicAuthSettings _basicAuthSettings;
|
||||
|
||||
public BasicAuthService(IOptionsMonitor<BasicAuthSettings> optionsMonitor)
|
||||
{
|
||||
_basicAuthSettings = optionsMonitor.CurrentValue;
|
||||
|
||||
optionsMonitor.OnChange(basicAuthSettings => _basicAuthSettings = basicAuthSettings);
|
||||
}
|
||||
|
||||
public bool IsBasicAuthEnabled() => _basicAuthSettings.Enabled;
|
||||
|
||||
public bool IsIpAllowListed(IPAddress clientIpAddress)
|
||||
{
|
||||
foreach (var allowedIpString in _basicAuthSettings.AllowedIPs)
|
||||
{
|
||||
if (IPNetwork.TryParse(allowedIpString, out IPNetwork allowedIp) && allowedIp.Contains(clientIpAddress))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,15 +19,16 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.34" />
|
||||
<PackageReference Include="MailKit" Version="2.13.0" />
|
||||
<PackageReference Include="MailKit" Version="2.14.0" />
|
||||
<PackageReference Include="IPNetwork2" Version="2.5.329" />
|
||||
<PackageReference Include="Markdown" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" />
|
||||
<PackageReference Include="MiniProfiler.Shared" Version="4.2.22" />
|
||||
<PackageReference Include="ncrontab" Version="3.3.1" />
|
||||
@@ -42,8 +43,8 @@
|
||||
<PackageReference Include="Serilog.Formatting.Compact.Reader" Version="1.0.5" />
|
||||
<PackageReference Include="Serilog.Settings.AppSettings" Version="2.2.2" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Map" Version="1.0.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.3" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
|
||||
|
||||
@@ -17,13 +17,12 @@ namespace Umbraco.Cms.Persistence.SqlCe
|
||||
|
||||
public int BulkInsertRecords<T>(IUmbracoDatabase database, IEnumerable<T> records)
|
||||
{
|
||||
var recordsA = records.ToArray();
|
||||
if (recordsA.Length == 0) return 0;
|
||||
if (!records.Any()) return 0;
|
||||
|
||||
var pocoData = database.PocoDataFactory.ForType(typeof(T));
|
||||
if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
|
||||
|
||||
return BulkInsertRecordsSqlCe(database, pocoData, recordsA);
|
||||
return BulkInsertRecordsSqlCe(database, pocoData, records.ToArray());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using CSharpTest.Net.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Serializes/Deserializes data to BTree data source for <see cref="ContentData"/>
|
||||
/// </summary>
|
||||
internal class ContentDataSerializer : ISerializer<ContentData>
|
||||
public class ContentDataSerializer : ISerializer<ContentData>
|
||||
{
|
||||
public ContentDataSerializer(IDictionaryOfPropertyDataSerializer dictionaryOfPropertyDataSerializer = null)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Configuration;
|
||||
using System.Configuration;
|
||||
using CSharpTest.Net.Collections;
|
||||
using CSharpTest.Net.Serialization;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
{
|
||||
internal class BTree
|
||||
public class BTree
|
||||
{
|
||||
public static BPlusTree<int, ContentNodeKit> GetTree(string filepath, bool exists, NuCacheSettings settings, ContentDataSerializer contentDataSerializer = null)
|
||||
{
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Deserialize the data into a <see cref="ContentCacheDataModel"/>
|
||||
/// </summary>
|
||||
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData);
|
||||
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the <see cref="ContentCacheDataModel"/>
|
||||
/// Serializes the <see cref="ContentCacheDataModel"/>
|
||||
/// </summary>
|
||||
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model);
|
||||
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.IO;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
{
|
||||
internal interface IDictionaryOfPropertyDataSerializer
|
||||
public interface IDictionaryOfPropertyDataSerializer
|
||||
{
|
||||
IDictionary<string, PropertyData[]> ReadFrom(Stream stream);
|
||||
void WriteTo(IDictionary<string, PropertyData[]> value, Stream stream);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
DateFormatString = "o"
|
||||
};
|
||||
private readonly JsonNameTable _propertyNameTable = new DefaultJsonNameTable();
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published)
|
||||
{
|
||||
if (stringData == null && byteData != null)
|
||||
throw new NotSupportedException($"{typeof(JsonContentNestedDataSerializer)} does not support byte[] serialization");
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
}
|
||||
}
|
||||
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
{
|
||||
// note that numeric values (which are Int32) are serialized without their
|
||||
// type (eg "value":1234) and JsonConvert by default deserializes them as Int64
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
|
||||
_options = defaultOptions
|
||||
.WithResolver(resolver)
|
||||
.WithCompression(MessagePackCompression.Lz4BlockArray);
|
||||
.WithCompression(MessagePackCompression.Lz4BlockArray)
|
||||
.WithSecurity(MessagePackSecurity.UntrustedData);
|
||||
}
|
||||
|
||||
public string ToJson(byte[] bin)
|
||||
@@ -48,12 +49,12 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
return json;
|
||||
}
|
||||
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published)
|
||||
{
|
||||
if (byteData != null)
|
||||
{
|
||||
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(byteData, _options);
|
||||
Expand(content, cacheModel);
|
||||
Expand(content, cacheModel, published);
|
||||
return cacheModel;
|
||||
}
|
||||
else if (stringData != null)
|
||||
@@ -61,7 +62,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
// NOTE: We don't really support strings but it's possible if manually used (i.e. tests)
|
||||
var bin = Convert.FromBase64String(stringData);
|
||||
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(bin, _options);
|
||||
Expand(content, cacheModel);
|
||||
Expand(content, cacheModel, published);
|
||||
return cacheModel;
|
||||
}
|
||||
else
|
||||
@@ -70,9 +71,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
}
|
||||
}
|
||||
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
{
|
||||
Compress(content, model);
|
||||
Compress(content, model, published);
|
||||
var bytes = MessagePackSerializer.Serialize(model, _options);
|
||||
return new ContentCacheDataSerializationResult(null, bytes);
|
||||
}
|
||||
@@ -80,7 +81,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Used during serialization to compress properties
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="published"></param>
|
||||
/// <remarks>
|
||||
/// This will essentially 'double compress' property data. The MsgPack data as a whole will already be compressed
|
||||
/// but this will go a step further and double compress property data so that it is stored in the nucache file
|
||||
@@ -88,11 +91,11 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// read/decompressed as a string to be displayed on the front-end. This allows for potentially a significant
|
||||
/// memory savings but could also affect performance of first rendering pages while decompression occurs.
|
||||
/// </remarks>
|
||||
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model)
|
||||
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
{
|
||||
foreach(var propertyAliasToData in model.PropertyData)
|
||||
{
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key, published))
|
||||
{
|
||||
foreach(var property in propertyAliasToData.Value.Where(x => x.Value != null && x.Value is string))
|
||||
{
|
||||
@@ -105,12 +108,14 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Used during deserialization to map the property data as lazy or expand the value
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="nestedData"></param>
|
||||
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData)
|
||||
/// <param name="published"></param>
|
||||
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData, bool published)
|
||||
{
|
||||
foreach (var propertyAliasToData in nestedData.PropertyData)
|
||||
{
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key,published))
|
||||
{
|
||||
foreach (var property in propertyAliasToData.Value.Where(x => x.Value != null))
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
{
|
||||
@@ -14,7 +13,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly IPropertyCacheCompressionOptions _compressionOptions;
|
||||
private readonly ConcurrentDictionary<(int, string), bool> _isCompressedCache = new ConcurrentDictionary<(int, string), bool>();
|
||||
private readonly ConcurrentDictionary<(int, string, bool), bool> _isCompressedCache = new ConcurrentDictionary<(int, string, bool), bool>();
|
||||
|
||||
public MsgPackContentNestedDataSerializerFactory(
|
||||
IContentTypeService contentTypeService,
|
||||
|
||||
@@ -68,7 +68,20 @@ namespace Umbraco.Extensions
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
});
|
||||
builder.Services.AddSingleton<IPropertyCacheCompressionOptions, NoopPropertyCacheCompressionOptions>();
|
||||
|
||||
builder.Services.AddSingleton<IPropertyCacheCompressionOptions>(s =>
|
||||
{
|
||||
IOptions<NuCacheSettings> options = s.GetRequiredService<IOptions<NuCacheSettings>>();
|
||||
|
||||
if (options.Value.NuCacheSerializerType == NuCacheSerializerType.MessagePack &&
|
||||
options.Value.UnPublishedContentCompression)
|
||||
{
|
||||
return new UnPublishedContentPropertyCacheCompressionOptions();
|
||||
}
|
||||
|
||||
return new NoopPropertyCacheCompressionOptions();
|
||||
});
|
||||
|
||||
builder.Services.AddSingleton(s => new ContentDataSerializer(new DictionaryOfPropertyDataSerializer()));
|
||||
|
||||
// add the NuCache health check (hidden from type finder)
|
||||
|
||||
@@ -415,7 +415,7 @@ AND cmsContentNu.nodeId IS NULL
|
||||
UrlSegment = content.GetUrlSegment(_shortStringHelper, _urlSegmentProviders)
|
||||
};
|
||||
|
||||
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData);
|
||||
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData, published);
|
||||
|
||||
var dto = new ContentNuDto
|
||||
{
|
||||
@@ -817,12 +817,13 @@ AND cmsContentNu.nodeId IS NULL
|
||||
}
|
||||
else
|
||||
{
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
|
||||
bool published = false;
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published);
|
||||
|
||||
d = new ContentData
|
||||
{
|
||||
Name = dto.EditName,
|
||||
Published = false,
|
||||
Published = published,
|
||||
TemplateId = dto.EditTemplateId,
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.EditVersionDate,
|
||||
@@ -847,13 +848,14 @@ AND cmsContentNu.nodeId IS NULL
|
||||
}
|
||||
else
|
||||
{
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw);
|
||||
bool published = true;
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw, published);
|
||||
|
||||
p = new ContentData
|
||||
{
|
||||
Name = dto.PubName,
|
||||
UrlSegment = deserializedContent.UrlSegment,
|
||||
Published = true,
|
||||
Published = published,
|
||||
TemplateId = dto.PubTemplateId,
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.PubVersionDate,
|
||||
@@ -883,12 +885,13 @@ AND cmsContentNu.nodeId IS NULL
|
||||
if (dto.EditData == null && dto.EditDataRaw == null)
|
||||
throw new InvalidOperationException("No data for media " + dto.Id);
|
||||
|
||||
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
|
||||
bool published = true;
|
||||
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published);
|
||||
|
||||
var p = new ContentData
|
||||
{
|
||||
Name = dto.EditName,
|
||||
Published = true,
|
||||
Published = published,
|
||||
TemplateId = -1,
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.EditVersionDate,
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MessagePack" Version="2.2.85" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.6" />
|
||||
<PackageReference Include="MessagePack" Version="2.3.75" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.12" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Umbraco.Code" Version="1.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
16
src/Umbraco.TestData/Configuration/TestDataSettings.cs
Normal file
16
src/Umbraco.TestData/Configuration/TestDataSettings.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Umbraco.TestData.Configuration
|
||||
{
|
||||
public class TestDataSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the test data generation is enabled.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether persisted local database cache files for content and media are disabled.
|
||||
/// </summary>
|
||||
/// <value>The URL path.</value>
|
||||
public bool IgnoreLocalDb { get; set; } = false;
|
||||
}
|
||||
}
|
||||
54
src/Umbraco.TestData/Extensions/UmbracoBuilderExtensions.cs
Normal file
54
src/Umbraco.TestData/Extensions/UmbracoBuilderExtensions.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Infrastructure.PublishedCache;
|
||||
using Umbraco.Cms.Web.Common.ApplicationBuilder;
|
||||
using Umbraco.TestData.Configuration;
|
||||
|
||||
namespace Umbraco.TestData.Extensions
|
||||
{
|
||||
public static class UmbracoBuilderExtensions
|
||||
{
|
||||
public static IUmbracoBuilder AddUmbracoTestData(this IUmbracoBuilder builder)
|
||||
{
|
||||
if (builder.Services.Any(x => x.ServiceType == typeof(LoadTestController)))
|
||||
{
|
||||
// We assume the test data project is composed if any implementations of LoadTestController exist.
|
||||
return builder;
|
||||
}
|
||||
|
||||
IConfigurationSection testDataSection = builder.Config.GetSection("Umbraco:CMS:TestData");
|
||||
TestDataSettings config = testDataSection.Get<TestDataSettings>();
|
||||
if (config == null || config.Enabled == false)
|
||||
{
|
||||
return builder;
|
||||
}
|
||||
|
||||
builder.Services.Configure<TestDataSettings>(testDataSection);
|
||||
|
||||
if (config.IgnoreLocalDb)
|
||||
{
|
||||
builder.Services.AddSingleton(factory => new PublishedSnapshotServiceOptions
|
||||
{
|
||||
IgnoreLocalDb = true
|
||||
});
|
||||
}
|
||||
|
||||
builder.Services.Configure<UmbracoPipelineOptions>(options =>
|
||||
options.AddFilter(new UmbracoPipelineFilter(nameof(LoadTestController))
|
||||
{
|
||||
Endpoints = app => app.UseEndpoints(endpoints =>
|
||||
endpoints.MapControllerRoute(
|
||||
"LoadTest",
|
||||
"/LoadTest/{action}",
|
||||
new { controller = "LoadTest", Action = "Index" }))
|
||||
}));
|
||||
|
||||
builder.Services.AddScoped(typeof(LoadTestController));
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Configuration;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
|
||||
// see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting
|
||||
|
||||
namespace Umbraco.TestData
|
||||
{
|
||||
public class LoadTestComponent : IComponent
|
||||
{
|
||||
public void Initialize()
|
||||
{
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
return;
|
||||
|
||||
|
||||
|
||||
RouteTable.Routes.MapRoute(
|
||||
name: "LoadTest",
|
||||
url: "LoadTest/{action}",
|
||||
defaults: new
|
||||
{
|
||||
controller = "LoadTest",
|
||||
action = "Index"
|
||||
},
|
||||
namespaces: new[] { "Umbraco.TestData" }
|
||||
);
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,13 @@
|
||||
using System.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Infrastructure.PublishedCache;
|
||||
using Umbraco.TestData.Extensions;
|
||||
|
||||
// see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting
|
||||
|
||||
namespace Umbraco.TestData
|
||||
{
|
||||
public class LoadTestComposer : ComponentComposer<LoadTestComponent>, IUserComposer
|
||||
public class LoadTestComposer : IUserComposer
|
||||
{
|
||||
public override void Compose(IUmbracoBuilder builder)
|
||||
{
|
||||
base.Compose(builder);
|
||||
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
return;
|
||||
|
||||
builder.Services.AddScoped(typeof(LoadTestController), typeof(LoadTestController));
|
||||
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.IgnoreLocalDb"] == "true")
|
||||
{
|
||||
builder.Services.AddSingleton(factory => new PublishedSnapshotServiceOptions
|
||||
{
|
||||
IgnoreLocalDb = true
|
||||
});
|
||||
}
|
||||
}
|
||||
public void Compose(IUmbracoBuilder builder) => builder.AddUmbracoTestData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using System.IO;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
|
||||
// see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting
|
||||
|
||||
@@ -23,27 +17,17 @@ namespace Umbraco.TestData
|
||||
{
|
||||
public class LoadTestController : Controller
|
||||
{
|
||||
public LoadTestController(
|
||||
ServiceContext serviceContext,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IHostingEnvironment hostingEnvironment)
|
||||
{
|
||||
_serviceContext = serviceContext;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
}
|
||||
private static readonly Random s_random = new Random();
|
||||
private static readonly object s_locko = new object();
|
||||
|
||||
private static readonly Random _random = new Random();
|
||||
private static readonly object _locko = new object();
|
||||
private static volatile int s_containerId = -1;
|
||||
|
||||
private static volatile int _containerId = -1;
|
||||
private const string ContainerAlias = "LoadTestContainer";
|
||||
private const string ContentAlias = "LoadTestContent";
|
||||
private const int TextboxDefinitionId = -88;
|
||||
private const int MaxCreate = 1000;
|
||||
|
||||
private const string _containerAlias = "LoadTestContainer";
|
||||
private const string _contentAlias = "LoadTestContent";
|
||||
private const int _textboxDefinitionId = -88;
|
||||
private const int _maxCreate = 1000;
|
||||
|
||||
private static readonly string HeadHtml = @"<html>
|
||||
private static readonly string s_headHtml = @"<html>
|
||||
<head>
|
||||
<title>LoadTest</title>
|
||||
<style>
|
||||
@@ -67,18 +51,18 @@ namespace Umbraco.TestData
|
||||
private const string FootHtml = @"</body>
|
||||
</html>";
|
||||
|
||||
private static readonly string _containerTemplateText = @"
|
||||
private static readonly string s_containerTemplateText = @"
|
||||
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
|
||||
@{
|
||||
Layout = null;
|
||||
var container = Umbraco.ContentAtRoot().OfTypes(""" + _containerAlias + @""").FirstOrDefault();
|
||||
var container = Umbraco.ContentAtRoot().OfTypes(""" + ContainerAlias + @""").FirstOrDefault();
|
||||
var contents = container.Children().ToArray();
|
||||
var groups = contents.GroupBy(x => x.Value<string>(""origin""));
|
||||
var id = contents.Length > 0 ? contents[0].Id : -1;
|
||||
var wurl = Request.QueryString[""u""] == ""1"";
|
||||
var missing = contents.Length > 0 && contents[contents.Length - 1].Id - contents[0].Id >= contents.Length;
|
||||
}
|
||||
" + HeadHtml + @"
|
||||
" + s_headHtml + @"
|
||||
<div class=""block"">
|
||||
<span @Html.Raw(missing ? ""style=\""color:red;\"""" : """")>@contents.Length items</span>
|
||||
<ul>
|
||||
@@ -106,19 +90,41 @@ namespace Umbraco.TestData
|
||||
}
|
||||
</div>
|
||||
" + FootHtml;
|
||||
private readonly ServiceContext _serviceContext;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
private ActionResult ContentHtml(string s)
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly Cms.Core.Hosting.IHostingEnvironment _hostingEnvironment;
|
||||
private readonly IHostApplicationLifetime _hostApplicationLifetime;
|
||||
|
||||
public LoadTestController(
|
||||
IContentTypeService contentTypeService,
|
||||
IContentService contentService,
|
||||
IDataTypeService dataTypeService,
|
||||
IFileService fileService,
|
||||
IShortStringHelper shortStringHelper,
|
||||
Cms.Core.Hosting.IHostingEnvironment hostingEnvironment,
|
||||
IHostApplicationLifetime hostApplicationLifetime)
|
||||
{
|
||||
return Content(HeadHtml + s + FootHtml);
|
||||
_contentTypeService = contentTypeService;
|
||||
_contentService = contentService;
|
||||
_dataTypeService = dataTypeService;
|
||||
_fileService = fileService;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_hostApplicationLifetime = hostApplicationLifetime;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
var res = EnsureInitialize();
|
||||
if (res != null) return res;
|
||||
IActionResult res = EnsureInitialize();
|
||||
if (res != null)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
var html = @"Welcome. You can:
|
||||
<ul>
|
||||
@@ -135,68 +141,71 @@ namespace Umbraco.TestData
|
||||
return ContentHtml(html);
|
||||
}
|
||||
|
||||
private ActionResult EnsureInitialize()
|
||||
private IActionResult EnsureInitialize()
|
||||
{
|
||||
if (_containerId > 0) return null;
|
||||
|
||||
lock (_locko)
|
||||
if (s_containerId > 0)
|
||||
{
|
||||
if (_containerId > 0) return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
var contentTypeService = _serviceContext.ContentTypeService;
|
||||
var contentType = contentTypeService.Get(_contentAlias);
|
||||
lock (s_locko)
|
||||
{
|
||||
if (s_containerId > 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IContentType contentType = _contentTypeService.Get(ContentAlias);
|
||||
if (contentType == null)
|
||||
{
|
||||
return ContentHtml("Not installed, first you must <a href=\"/LoadTest/Install\">install</a>.");
|
||||
}
|
||||
|
||||
var containerType = contentTypeService.Get(_containerAlias);
|
||||
IContentType containerType = _contentTypeService.Get(ContainerAlias);
|
||||
if (containerType == null)
|
||||
{
|
||||
return ContentHtml("Panic! Container type is missing.");
|
||||
}
|
||||
|
||||
var contentService = _serviceContext.ContentService;
|
||||
var container = contentService.GetPagedOfType(containerType.Id, 0, 100, out _, null).FirstOrDefault();
|
||||
IContent container = _contentService.GetPagedOfType(containerType.Id, 0, 100, out _, null).FirstOrDefault();
|
||||
if (container == null)
|
||||
{
|
||||
return ContentHtml("Panic! Container is missing.");
|
||||
}
|
||||
|
||||
_containerId = container.Id;
|
||||
s_containerId = container.Id;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult Install()
|
||||
private IActionResult ContentHtml(string s) => Content(s_headHtml + s + FootHtml);
|
||||
|
||||
public IActionResult Install()
|
||||
{
|
||||
var dataTypeService = _serviceContext.DataTypeService;
|
||||
|
||||
//var dataType = dataTypeService.GetAll(Constants.DataTypes.DefaultContentListView);
|
||||
|
||||
|
||||
//if (!dict.ContainsKey("pageSize")) dict["pageSize"] = new PreValue("10");
|
||||
//dict["pageSize"].Value = "200";
|
||||
//dataTypeService.SavePreValues(dataType, dict);
|
||||
|
||||
var contentTypeService = _serviceContext.ContentTypeService;
|
||||
|
||||
var contentType = new ContentType(_shortStringHelper, -1)
|
||||
{
|
||||
Alias = _contentAlias,
|
||||
Alias = ContentAlias,
|
||||
Name = "LoadTest Content",
|
||||
Description = "Content for LoadTest",
|
||||
Icon = "icon-document"
|
||||
};
|
||||
var def = _serviceContext.DataTypeService.GetDataType(_textboxDefinitionId);
|
||||
IDataType def = _dataTypeService.GetDataType(TextboxDefinitionId);
|
||||
contentType.AddPropertyType(new PropertyType(_shortStringHelper, def)
|
||||
{
|
||||
Name = "Origin",
|
||||
Alias = "origin",
|
||||
Description = "The origin of the content.",
|
||||
});
|
||||
contentTypeService.Save(contentType);
|
||||
_contentTypeService.Save(contentType);
|
||||
|
||||
var containerTemplate = ImportTemplate(_serviceContext, _shortStringHelper,
|
||||
"LoadTestContainer", "LoadTestContainer", _containerTemplateText);
|
||||
Template containerTemplate = ImportTemplate(
|
||||
"LoadTestContainer",
|
||||
"LoadTestContainer",
|
||||
s_containerTemplateText);
|
||||
|
||||
var containerType = new ContentType(_shortStringHelper, -1)
|
||||
{
|
||||
Alias = _containerAlias,
|
||||
Alias = ContainerAlias,
|
||||
Name = "LoadTest Container",
|
||||
Description = "Container for LoadTest content",
|
||||
Icon = "icon-document",
|
||||
@@ -209,59 +218,92 @@ namespace Umbraco.TestData
|
||||
});
|
||||
containerType.AllowedTemplates = containerType.AllowedTemplates.Union(new[] { containerTemplate });
|
||||
containerType.SetDefaultTemplate(containerTemplate);
|
||||
contentTypeService.Save(containerType);
|
||||
_contentTypeService.Save(containerType);
|
||||
|
||||
var contentService = _serviceContext.ContentService;
|
||||
var content = contentService.Create("LoadTestContainer", -1, _containerAlias);
|
||||
contentService.SaveAndPublish(content);
|
||||
IContent content = _contentService.Create("LoadTestContainer", -1, ContainerAlias);
|
||||
_contentService.SaveAndPublish(content);
|
||||
|
||||
return ContentHtml("Installed.");
|
||||
}
|
||||
|
||||
public ActionResult Create(int n = 1, int r = 0, string o = null)
|
||||
private Template ImportTemplate(string name, string alias, string text, ITemplate master = null)
|
||||
{
|
||||
var res = EnsureInitialize();
|
||||
if (res != null) return res;
|
||||
var t = new Template(_shortStringHelper, name, alias) { Content = text };
|
||||
if (master != null)
|
||||
{
|
||||
t.SetMasterTemplate(master);
|
||||
}
|
||||
|
||||
_fileService.SaveTemplate(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public IActionResult Create(int n = 1, int r = 0, string o = null)
|
||||
{
|
||||
IActionResult res = EnsureInitialize();
|
||||
if (res != null)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (r > 100)
|
||||
{
|
||||
r = 100;
|
||||
}
|
||||
|
||||
if (r < 0) r = 0;
|
||||
if (r > 100) r = 100;
|
||||
var restart = GetRandom(0, 100) > (100 - r);
|
||||
|
||||
var contentService = _serviceContext.ContentService;
|
||||
if (n < 1)
|
||||
{
|
||||
n = 1;
|
||||
}
|
||||
|
||||
if (n > MaxCreate)
|
||||
{
|
||||
n = MaxCreate;
|
||||
}
|
||||
|
||||
if (n < 1) n = 1;
|
||||
if (n > _maxCreate) n = _maxCreate;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var name = Guid.NewGuid().ToString("N").ToUpper() + "-" + (restart ? "R" : "X") + "-" + o;
|
||||
var content = contentService.Create(name, _containerId, _contentAlias);
|
||||
IContent content = _contentService.Create(name, s_containerId, ContentAlias);
|
||||
content.SetValue("origin", o);
|
||||
contentService.SaveAndPublish(content);
|
||||
_contentService.SaveAndPublish(content);
|
||||
}
|
||||
|
||||
if (restart)
|
||||
{
|
||||
DoRestart();
|
||||
}
|
||||
|
||||
return ContentHtml("Created " + n + " content"
|
||||
+ (restart ? ", and restarted" : "")
|
||||
+ ".");
|
||||
}
|
||||
|
||||
private int GetRandom(int minValue, int maxValue)
|
||||
private static int GetRandom(int minValue, int maxValue)
|
||||
{
|
||||
lock (_locko)
|
||||
lock (s_locko)
|
||||
{
|
||||
return _random.Next(minValue, maxValue);
|
||||
return s_random.Next(minValue, maxValue);
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult Clear()
|
||||
public IActionResult Clear()
|
||||
{
|
||||
var res = EnsureInitialize();
|
||||
if (res != null) return res;
|
||||
IActionResult res = EnsureInitialize();
|
||||
if (res != null)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
var contentType = _serviceContext.ContentTypeService.Get(_contentAlias);
|
||||
_serviceContext.ContentService.DeleteOfType(contentType.Id);
|
||||
IContentType contentType = _contentTypeService.Get(ContentAlias);
|
||||
_contentService.DeleteOfType(contentType.Id);
|
||||
|
||||
return ContentHtml("Cleared.");
|
||||
}
|
||||
@@ -269,12 +311,11 @@ namespace Umbraco.TestData
|
||||
private void DoRestart()
|
||||
{
|
||||
HttpContext.User = null;
|
||||
System.Web.HttpContext.Current.User = null;
|
||||
Thread.CurrentPrincipal = null;
|
||||
HttpRuntime.UnloadAppDomain();
|
||||
_hostApplicationLifetime.StopApplication();
|
||||
}
|
||||
|
||||
public ActionResult ColdBootRestart()
|
||||
public IActionResult ColdBootRestart()
|
||||
{
|
||||
Directory.Delete(_hostingEnvironment.MapPathContentRoot(Path.Combine(Constants.SystemDirectories.TempData,"DistCache")), true);
|
||||
|
||||
@@ -283,35 +324,38 @@ namespace Umbraco.TestData
|
||||
return Content("Cold Boot Restarted.");
|
||||
}
|
||||
|
||||
public ActionResult Restart()
|
||||
public IActionResult Restart()
|
||||
{
|
||||
DoRestart();
|
||||
|
||||
return ContentHtml("Restarted.");
|
||||
}
|
||||
|
||||
public ActionResult Die()
|
||||
public IActionResult Die()
|
||||
{
|
||||
var timer = new System.Threading.Timer(_ =>
|
||||
{
|
||||
throw new Exception("die!");
|
||||
});
|
||||
timer.Change(100, 0);
|
||||
var timer = new Timer(_ => throw new Exception("die!"));
|
||||
_ = timer.Change(100, 0);
|
||||
|
||||
return ContentHtml("Dying.");
|
||||
}
|
||||
|
||||
public ActionResult Domains()
|
||||
public IActionResult Domains()
|
||||
{
|
||||
var currentDomain = AppDomain.CurrentDomain;
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
var currentName = currentDomain.FriendlyName;
|
||||
var pos = currentName.IndexOf('-');
|
||||
if (pos > 0) currentName = currentName.Substring(0, pos);
|
||||
if (pos > 0)
|
||||
{
|
||||
currentName = currentName.Substring(0, pos);
|
||||
}
|
||||
|
||||
var text = new System.Text.StringBuilder();
|
||||
var text = new StringBuilder();
|
||||
text.Append("<div class=\"block\">Process ID: " + Process.GetCurrentProcess().Id + "</div>");
|
||||
text.Append("<div class=\"block\">");
|
||||
text.Append("<div>IIS Site: " + HostingEnvironment.ApplicationHost.GetSiteName() + "</div>");
|
||||
|
||||
// TODO (V9): Commented out as I assume not available?
|
||||
////text.Append("<div>IIS Site: " + HostingEnvironment.ApplicationHost.GetSiteName() + "</div>");
|
||||
|
||||
text.Append("<div>App ID: " + currentName + "</div>");
|
||||
//text.Append("<div>AppPool: " + Zbu.WebManagement.AppPoolHelper.GetCurrentApplicationPoolName() + "</div>");
|
||||
text.Append("</div>");
|
||||
@@ -338,56 +382,5 @@ namespace Umbraco.TestData
|
||||
|
||||
return ContentHtml(text.ToString());
|
||||
}
|
||||
|
||||
public ActionResult Recycle()
|
||||
{
|
||||
return ContentHtml("Not implemented—please use IIS console.");
|
||||
}
|
||||
|
||||
private static Template ImportTemplate(ServiceContext svces, IShortStringHelper shortStringHelper, string name, string alias, string text, ITemplate master = null)
|
||||
{
|
||||
var t = new Template(shortStringHelper, name, alias) { Content = text };
|
||||
if (master != null)
|
||||
t.SetMasterTemplate(master);
|
||||
svces.FileService.SaveTemplate(t);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestComponent : IComponent
|
||||
{
|
||||
public void Initialize()
|
||||
{
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
return;
|
||||
|
||||
RouteTable.Routes.MapRoute(
|
||||
name: "LoadTest",
|
||||
url: "LoadTest/{action}",
|
||||
defaults: new
|
||||
{
|
||||
controller = "LoadTest",
|
||||
action = "Index"
|
||||
},
|
||||
namespaces: new[] { "Umbraco.TestData" }
|
||||
);
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class TestComposer : ComponentComposer<TestComponent>, IUserComposer
|
||||
{
|
||||
public override void Compose(IUmbracoBuilder builder)
|
||||
{
|
||||
base.Compose(builder);
|
||||
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
return;
|
||||
|
||||
builder.Services.AddScoped(typeof(LoadTestController));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Umbraco.TestData")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Umbraco.TestData")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("fb5676ed-7a69-492c-b802-e7b24144c0fc")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,31 +1,55 @@
|
||||
using System.Configuration;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Web.Website.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.TestData
|
||||
{
|
||||
public class SegmentTestController : SurfaceController
|
||||
{
|
||||
public SegmentTestController(
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
ServiceContext services,
|
||||
AppCaches appCaches,
|
||||
IProfilingLogger profilingLogger,
|
||||
IPublishedUrlProvider publishedUrlProvider)
|
||||
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public ActionResult EnableDocTypeSegments(string alias, string propertyTypeAlias)
|
||||
public IActionResult EnableDocTypeSegments(string alias, string propertyTypeAlias)
|
||||
{
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var ct = Services.ContentTypeService.Get(alias);
|
||||
IContentType ct = Services.ContentTypeService.Get(alias);
|
||||
if (ct == null)
|
||||
{
|
||||
return Content($"No document type found by alias {alias}");
|
||||
}
|
||||
|
||||
var propType = ct.PropertyTypes.FirstOrDefault(x => x.Alias == propertyTypeAlias);
|
||||
IPropertyType propType = ct.PropertyTypes.FirstOrDefault(x => x.Alias == propertyTypeAlias);
|
||||
if (propType == null)
|
||||
{
|
||||
return Content($"The document type {alias} does not have a property type {propertyTypeAlias ?? "null"}");
|
||||
}
|
||||
|
||||
if (ct.Variations.VariesBySegment())
|
||||
{
|
||||
return Content($"The document type {alias} already allows segments, nothing has been changed");
|
||||
}
|
||||
|
||||
ct.SetVariesBy(ContentVariation.Segment);
|
||||
propType.SetVariesBy(ContentVariation.Segment);
|
||||
@@ -34,17 +58,25 @@ namespace Umbraco.TestData
|
||||
return Content($"The document type {alias} and property type {propertyTypeAlias} now allows segments");
|
||||
}
|
||||
|
||||
public ActionResult DisableDocTypeSegments(string alias)
|
||||
private IActionResult HttpNotFound() => throw new NotImplementedException();
|
||||
|
||||
public IActionResult DisableDocTypeSegments(string alias)
|
||||
{
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var ct = Services.ContentTypeService.Get(alias);
|
||||
IContentType ct = Services.ContentTypeService.Get(alias);
|
||||
if (ct == null)
|
||||
{
|
||||
return Content($"No document type found by alias {alias}");
|
||||
}
|
||||
|
||||
if (!ct.VariesBySegment())
|
||||
{
|
||||
return Content($"The document type {alias} does not allow segments, nothing has been changed");
|
||||
}
|
||||
|
||||
ct.SetVariesBy(ContentVariation.Segment, false);
|
||||
|
||||
@@ -54,21 +86,31 @@ namespace Umbraco.TestData
|
||||
|
||||
public ActionResult AddSegmentData(int contentId, string propertyAlias, string value, string segment, string culture = null)
|
||||
{
|
||||
var content = Services.ContentService.GetById(contentId);
|
||||
IContent content = Services.ContentService.GetById(contentId);
|
||||
if (content == null)
|
||||
{
|
||||
return Content($"No content found by id {contentId}");
|
||||
}
|
||||
|
||||
if (propertyAlias.IsNullOrWhiteSpace() || !content.HasProperty(propertyAlias))
|
||||
{
|
||||
return Content($"The content by id {contentId} does not contain a property with alias {propertyAlias ?? "null"}");
|
||||
}
|
||||
|
||||
if (content.ContentType.VariesByCulture() && culture.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Content($"The content by id {contentId} varies by culture but no culture was specified");
|
||||
}
|
||||
|
||||
if (value.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Content("'value' cannot be null");
|
||||
}
|
||||
|
||||
if (segment.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Content("'segment' cannot be null");
|
||||
}
|
||||
|
||||
content.SetValue(propertyAlias, value, culture, segment);
|
||||
Services.ContentService.Save(content);
|
||||
|
||||
@@ -1,82 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{FB5676ED-7A69-492C-B802-E7B24144C0FC}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>Umbraco.TestData</RootNamespace>
|
||||
<AssemblyName>Umbraco.TestData</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<LangVersion>8</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<PackageReference Include="Bogus" Version="33.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="LoadTestComponent.cs" />
|
||||
<Compile Include="LoadTestComposer.cs" />
|
||||
<Compile Include="LoadTestController.cs" />
|
||||
<Compile Include="SegmentTestController.cs" />
|
||||
<Compile Include="UmbracoTestDataController.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.Common\Umbraco.Web.Common.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.Website\Umbraco.Web.Website.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="readme.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
<Project>{29aa69d9-b597-4395-8d42-43b1263c240a}</Project>
|
||||
<Name>Umbraco.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj">
|
||||
<Project>{3ae7bf57-966b-45a5-910a-954d7c554441}</Project>
|
||||
<Name>Umbraco.Infrastructure</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj">
|
||||
<Project>{f6de8da0-07cc-4ef2-8a59-2bc81dbb3830}</Project>
|
||||
<Name>Umbraco.PublishedCache.NuCache</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.Web\Umbraco.Web.csproj">
|
||||
<Project>{651e1350-91b6-44b7-bd60-7207006d7003}</Project>
|
||||
<Name>Umbraco.Web</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bogus">
|
||||
<Version>33.0.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNet.Mvc">
|
||||
<Version>5.2.7</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Bogus;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
using Umbraco.Cms.Web.Website.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.TestData.Configuration;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
namespace Umbraco.TestData
|
||||
@@ -33,13 +35,25 @@ namespace Umbraco.TestData
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly TestDataSettings _testDataSettings;
|
||||
|
||||
public UmbracoTestDataController(IScopeProvider scopeProvider, PropertyEditorCollection propertyEditors, IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IShortStringHelper shortStringHelper)
|
||||
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger)
|
||||
public UmbracoTestDataController(
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
ServiceContext services,
|
||||
AppCaches appCaches,
|
||||
IProfilingLogger profilingLogger,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
IScopeProvider scopeProvider,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IOptions<TestDataSettings> testDataSettings)
|
||||
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
_propertyEditors = propertyEditors;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_testDataSettings = testDataSettings.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,18 +66,22 @@ namespace Umbraco.TestData
|
||||
/// <remarks>
|
||||
/// Each content item created is associated to a media item via a media picker and therefore a relation is created between the two
|
||||
/// </remarks>
|
||||
public ActionResult CreateTree(int count, int depth, string locale = "en")
|
||||
public IActionResult CreateTree(int count, int depth, string locale = "en")
|
||||
{
|
||||
if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true")
|
||||
return HttpNotFound();
|
||||
if (_testDataSettings.Enabled == false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!Validate(count, depth, out var message, out var perLevel))
|
||||
{
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
var faker = new Faker(locale);
|
||||
var company = faker.Company.CompanyName();
|
||||
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
using (IScope scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
var imageIds = CreateMediaTree(company, faker, count, depth).ToList();
|
||||
var contentIds = CreateContentTree(company, faker, count, depth, imageIds, out var root).ToList();
|
||||
@@ -77,7 +95,7 @@ namespace Umbraco.TestData
|
||||
return Content("Done");
|
||||
}
|
||||
|
||||
private bool Validate(int count, int depth, out string message, out int perLevel)
|
||||
private static bool Validate(int count, int depth, out string message, out int perLevel)
|
||||
{
|
||||
perLevel = 0;
|
||||
message = null;
|
||||
@@ -128,8 +146,8 @@ namespace Umbraco.TestData
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var created = create(parent);
|
||||
var contentItem = created.content;
|
||||
(T content, Func<T> container) created = create(parent);
|
||||
T contentItem = created.content;
|
||||
|
||||
yield return contentItem.GetUdi();
|
||||
|
||||
@@ -139,7 +157,7 @@ namespace Umbraco.TestData
|
||||
{
|
||||
// move back up...
|
||||
|
||||
var prev = tracked.Pop();
|
||||
(T parent, int childCount) prev = tracked.Pop();
|
||||
|
||||
// restore child count
|
||||
currChildCount = prev.childCount;
|
||||
@@ -171,7 +189,7 @@ namespace Umbraco.TestData
|
||||
/// <returns></returns>
|
||||
private IEnumerable<Udi> CreateMediaTree(string company, Faker faker, int count, int depth)
|
||||
{
|
||||
var parent = Services.MediaService.CreateMediaWithIdentity(company, -1, Constants.Conventions.MediaTypes.Folder);
|
||||
IMedia parent = Services.MediaService.CreateMediaWithIdentity(company, -1, Constants.Conventions.MediaTypes.Folder);
|
||||
|
||||
return CreateHierarchy(parent, count, depth, currParent =>
|
||||
{
|
||||
@@ -185,13 +203,13 @@ namespace Umbraco.TestData
|
||||
// if we don't do this we don't get thumbnails in the back office.
|
||||
imageUrl += "&ext=.jpg";
|
||||
|
||||
var media = Services.MediaService.CreateMedia(faker.Commerce.ProductName(), currParent, Constants.Conventions.MediaTypes.Image);
|
||||
IMedia media = Services.MediaService.CreateMedia(faker.Commerce.ProductName(), currParent, Constants.Conventions.MediaTypes.Image);
|
||||
media.SetValue(Constants.Conventions.Media.File, imageUrl);
|
||||
Services.MediaService.Save(media);
|
||||
return (media, () =>
|
||||
{
|
||||
// create a folder to contain child media
|
||||
var container = Services.MediaService.CreateMediaWithIdentity(faker.Commerce.Department(), currParent, Constants.Conventions.MediaTypes.Folder);
|
||||
IMedia container = Services.MediaService.CreateMediaWithIdentity(faker.Commerce.Department(), currParent, Constants.Conventions.MediaTypes.Folder);
|
||||
return container;
|
||||
});
|
||||
});
|
||||
@@ -210,9 +228,10 @@ namespace Umbraco.TestData
|
||||
{
|
||||
var random = new Random(company.GetHashCode());
|
||||
|
||||
var docType = GetOrCreateContentType();
|
||||
IContentType docType = GetOrCreateContentType();
|
||||
|
||||
IContent parent = Services.ContentService.Create(company, -1, docType.Alias);
|
||||
|
||||
var parent = Services.ContentService.Create(company, -1, docType.Alias);
|
||||
// give it some reasonable data (100 reviews)
|
||||
parent.SetValue("review", string.Join(" ", Enumerable.Range(0, 100).Select(x => faker.Rant.Review())));
|
||||
parent.SetValue("desc", company);
|
||||
@@ -223,7 +242,8 @@ namespace Umbraco.TestData
|
||||
|
||||
return CreateHierarchy(parent, count, depth, currParent =>
|
||||
{
|
||||
var content = Services.ContentService.Create(faker.Commerce.ProductName(), currParent, docType.Alias);
|
||||
IContent content = Services.ContentService.Create(faker.Commerce.ProductName(), currParent, docType.Alias);
|
||||
|
||||
// give it some reasonable data (100 reviews)
|
||||
content.SetValue("review", string.Join(" ", Enumerable.Range(0, 100).Select(x => faker.Rant.Review())));
|
||||
content.SetValue("desc", string.Join(", ", Enumerable.Range(0, 5).Select(x => faker.Commerce.ProductAdjective())));
|
||||
@@ -237,9 +257,11 @@ namespace Umbraco.TestData
|
||||
|
||||
private IContentType GetOrCreateContentType()
|
||||
{
|
||||
var docType = Services.ContentTypeService.Get(TestDataContentTypeAlias);
|
||||
IContentType docType = Services.ContentTypeService.Get(TestDataContentTypeAlias);
|
||||
if (docType != null)
|
||||
{
|
||||
return docType;
|
||||
}
|
||||
|
||||
docType = new ContentType(_shortStringHelper, -1)
|
||||
{
|
||||
@@ -274,12 +296,17 @@ namespace Umbraco.TestData
|
||||
|
||||
private IDataType GetOrCreateDataType(string name, string editorAlias)
|
||||
{
|
||||
var dt = Services.DataTypeService.GetDataType(name);
|
||||
if (dt != null) return dt;
|
||||
IDataType dt = Services.DataTypeService.GetDataType(name);
|
||||
if (dt != null)
|
||||
{
|
||||
return dt;
|
||||
}
|
||||
|
||||
var editor = _propertyEditors.FirstOrDefault(x => x.Alias == editorAlias);
|
||||
IDataEditor editor = _propertyEditors.FirstOrDefault(x => x.Alias == editorAlias);
|
||||
if (editor == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No {editorAlias} editor found");
|
||||
}
|
||||
|
||||
var serializer = new ConfigurationEditorJsonSerializer();
|
||||
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
## Umbraco Test Data
|
||||
## Umbraco Test Data
|
||||
|
||||
This project is a utility to be able to generate large amounts of content and media in an
|
||||
Umbraco installation for testing.
|
||||
|
||||
Currently this project is referenced in the Umbraco.Web.UI project but only when it's being built
|
||||
in Debug mode (i.e. when testing within Visual Studio).
|
||||
|
||||
## Usage
|
||||
|
||||
You must use SQL Server for this, using SQLCE will die if you try to bulk create huge amounts of data.
|
||||
|
||||
It has to be enabled by an appSetting:
|
||||
|
||||
```xml
|
||||
<add key="Umbraco.TestData.Enabled" value="true"/>
|
||||
```json
|
||||
{
|
||||
"Umbraco": {
|
||||
"CMS": {
|
||||
"TestData": {
|
||||
"Enabled" : true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once this is enabled this endpoint can be executed:
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<PackageReference Include="Moq" Version="4.13.1" />
|
||||
<PackageReference Include="AutoFixture.NUnit3" Version="4.17.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
@@ -18,20 +18,21 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest]
|
||||
[Platform("Win")]
|
||||
public class DatabaseBuilderTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IDbProviderFactoryCreator DbProviderFactoryCreator => GetRequiredService<IDbProviderFactoryCreator>();
|
||||
private IUmbracoDatabaseFactory UmbracoDatabaseFactory => GetRequiredService<IUmbracoDatabaseFactory>();
|
||||
private IEmbeddedDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService<IEmbeddedDatabaseCreator>();
|
||||
|
||||
public DatabaseBuilderTests()
|
||||
{
|
||||
TestOptionAttributeBase.ScanAssemblies.Add(typeof(DatabaseBuilderTests).Assembly);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateDatabase()
|
||||
{
|
||||
if (!TestEnvironment.IsWindows)
|
||||
{
|
||||
return; //TODO replace with [Platform("Win")] when we update to NUnit 3.13 + .NET 5
|
||||
}
|
||||
|
||||
var path = TestContext.CurrentContext.TestDirectory.Split("bin")[0];
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", path);
|
||||
const string dbFile = "DatabaseContextTests.sdf";
|
||||
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Examine.Lucene" Version="2.0.0-beta.154" />
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Tests.Common\Umbraco.Tests.Common.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Tests.Integration\Umbraco.Tests.Integration.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.Website\Umbraco.Web.Website.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Persistence.SqlCe\Umbraco.Persistence.SqlCe.csproj" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,106 +1,106 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>Umbraco.Cms.Tests.Integration</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RootNamespace>Umbraco.Cms.Tests.Integration</RootNamespace>
|
||||
<PackageId>Umbraco.Cms.Tests.Integration</PackageId>
|
||||
<Title>Umbraco CMS Integration Tests</Title>
|
||||
<Description>Contains helper classes for integration tests with Umbraco, including all internal integration tests.</Description>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
|
||||
<DefineConstants>IS_WINDOWS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
|
||||
<DefineConstants>IS_WINDOWS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="App_Data\**" />
|
||||
<Compile Remove="TEMP\**" />
|
||||
<Compile Remove="Umbraco\**" />
|
||||
<EmbeddedResource Remove="App_Data\**" />
|
||||
<EmbeddedResource Remove="TEMP\**" />
|
||||
<EmbeddedResource Remove="Umbraco\**" />
|
||||
<None Remove="App_Data\**" />
|
||||
<None Remove="TEMP\**" />
|
||||
<Compile Remove="Views\**" />
|
||||
<EmbeddedResource Remove="Views\**" />
|
||||
<None Remove="Umbraco\**" />
|
||||
<None Remove="Views\**" />
|
||||
<None Remove="create_slicing_filter_condition.sh" />
|
||||
<None Remove="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles\media.xml" />
|
||||
<EmbeddedResource Update="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>TestFiles.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Umbraco.Infrastructure\Services\Importing\ImportResources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>ImportResources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Update="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>TestFiles.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Umbraco.Infrastructure\Services\Importing\ImportResources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>ImportResources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="App_Data\**" />
|
||||
<Compile Remove="TEMP\**" />
|
||||
<Compile Remove="Umbraco\**" />
|
||||
<EmbeddedResource Remove="App_Data\**" />
|
||||
<EmbeddedResource Remove="TEMP\**" />
|
||||
<EmbeddedResource Remove="Umbraco\**" />
|
||||
<None Remove="App_Data\**" />
|
||||
<None Remove="TEMP\**" />
|
||||
<Compile Remove="Views\**" />
|
||||
<EmbeddedResource Remove="Views\**" />
|
||||
<None Remove="Umbraco\**" />
|
||||
<None Remove="Views\**" />
|
||||
<None Remove="create_slicing_filter_condition.sh" />
|
||||
<None Remove="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles\media.xml" />
|
||||
<EmbeddedResource Update="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>TestFiles.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Umbraco.Infrastructure\Services\Importing\ImportResources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>ImportResources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Update="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>TestFiles.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Umbraco.Infrastructure\Services\Importing\ImportResources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>ImportResources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Umbraco.Infrastructure\Services\Importing\Dictionary-Package.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Umbraco.Infrastructure\Services\Importing\Dictionary-Package.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles\media.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\CheckboxList-Content-Package.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\CompositionsTestPackage-Random.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\CompositionsTestPackage.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\Dictionary-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\Fanoe-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\InheritedDocTypes-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\SingleDocType.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\StandardMvc-Package.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\TemplateOnly-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\TemplateOnly-Updated-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\uBlogsy-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\XsltSearch-Package.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles\media.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\CheckboxList-Content-Package.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\CompositionsTestPackage-Random.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\CompositionsTestPackage.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\Dictionary-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\Fanoe-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\InheritedDocTypes-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\SingleDocType.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\StandardMvc-Package.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\TemplateOnly-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\TemplateOnly-Updated-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\uBlogsy-Package.xml" />
|
||||
<Content Include="Umbraco.Infrastructure\Services\Importing\XsltSearch-Package.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Examine.Lucene" Version="2.0.0-beta.154" />
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Examine.Lucene" Version="2.0.0-beta.154" />
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Tests.Common\Umbraco.Tests.Common.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.UI.NetCore\Umbraco.Web.UI.NetCore.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.Website\Umbraco.Web.Website.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Persistence.SqlCe\Umbraco.Persistence.SqlCe.csproj" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Tests.Common\Umbraco.Tests.Common.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.Website\Umbraco.Web.Website.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles\umbraco-sort.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Umbraco.Examine.Lucene\UmbracoExamine\TestFiles\umbraco-sort.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using NUnit.Framework;
|
||||
@@ -15,6 +15,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Configuration.Models
|
||||
[TestCase(null, ExpectedResult = null)]
|
||||
[TestCase(@"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;", ExpectedResult = Constants.DbProviderNames.SqlCe)]
|
||||
[TestCase(@"Server=(LocalDb)\Umbraco;Database=NetCore;Integrated Security=true", ExpectedResult = Constants.DbProviderNames.SqlServer)]
|
||||
[TestCase(@"Data Source=(LocalDb)\Umbraco;Initial Catalog=NetCore;Integrated Security=true;", ExpectedResult = Constants.DbProviderNames.SqlServer)]
|
||||
[TestCase(@"Data Source=.\SQLExpress;Integrated Security=true;AttachDbFilename=MyDataFile.mdf;", ExpectedResult = Constants.DbProviderNames.SqlServer)]
|
||||
public string ParseProviderName(string connectionString)
|
||||
{
|
||||
var connectionStrings = new ConnectionStrings
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Services
|
||||
{
|
||||
[TestFixture]
|
||||
public class BasicAuthServiceTests
|
||||
{
|
||||
[TestCase(true, ExpectedResult = true)]
|
||||
[TestCase(false, ExpectedResult = false)]
|
||||
public bool IsBasicAuthEnabled(bool enabled)
|
||||
{
|
||||
var sut = new BasicAuthService(Mock.Of<IOptionsMonitor<BasicAuthSettings>>(_ => _.CurrentValue == new BasicAuthSettings() {Enabled = enabled}));
|
||||
|
||||
return sut.IsBasicAuthEnabled();
|
||||
}
|
||||
|
||||
[TestCase("::1", "1.1.1.1", ExpectedResult = false)]
|
||||
[TestCase("::1", "1.1.1.1, ::1", ExpectedResult = true)]
|
||||
[TestCase("127.0.0.1", "127.0.0.1, ::1", ExpectedResult = true)]
|
||||
[TestCase("127.0.0.1", "", ExpectedResult = false)]
|
||||
[TestCase("125.125.125.1", "125.125.125.0/24", ExpectedResult = true)]
|
||||
[TestCase("125.125.124.1", "125.125.125.0/24", ExpectedResult = false)]
|
||||
public bool IsIpAllowListed(string clientIpAddress, string commaSeperatedAllowlist)
|
||||
{
|
||||
var allowedIPs = commaSeperatedAllowlist.Split(",").Select(x=>x.Trim()).ToArray();
|
||||
var sut = new BasicAuthService(Mock.Of<IOptionsMonitor<BasicAuthSettings>>(_ => _.CurrentValue == new BasicAuthSettings() {AllowedIPs = allowedIPs}));
|
||||
|
||||
return sut.IsIpAllowListed(IPAddress.Parse(clientIpAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,11 @@ namespace Umbraco.Cms.Web.Common.PublishedModels
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
public new const PublishedItemType ModelItemType = PublishedItemType.Content;
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
[return: global::System.Diagnostics.CodeAnalysis.MaybeNull]
|
||||
public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor)
|
||||
=> PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias);
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
[return: global::System.Diagnostics.CodeAnalysis.MaybeNull]
|
||||
public static IPublishedPropertyType GetModelPropertyType<TValue>(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression<Func<Type1, TValue>> selector)
|
||||
=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);
|
||||
#pragma warning restore 0109
|
||||
@@ -96,6 +98,7 @@ namespace Umbraco.Cms.Web.Common.PublishedModels
|
||||
// properties
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
[global::System.Diagnostics.CodeAnalysis.MaybeNull]
|
||||
[ImplementPropertyType(""prop1"")]
|
||||
public virtual string Prop1 => this.Value<string>(_publishedValueFallback, ""prop1"");
|
||||
}
|
||||
@@ -183,9 +186,11 @@ namespace Umbraco.Cms.Web.Common.PublishedModels
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
public new const PublishedItemType ModelItemType = PublishedItemType.Content;
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
[return: global::System.Diagnostics.CodeAnalysis.MaybeNull]
|
||||
public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor)
|
||||
=> PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias);
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
[return: global::System.Diagnostics.CodeAnalysis.MaybeNull]
|
||||
public static IPublishedPropertyType GetModelPropertyType<TValue>(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression<Func<Type1, TValue>> selector)
|
||||
=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);
|
||||
#pragma warning restore 0109
|
||||
@@ -202,6 +207,7 @@ namespace Umbraco.Cms.Web.Common.PublishedModels
|
||||
// properties
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")]
|
||||
[global::System.Diagnostics.CodeAnalysis.MaybeNull]
|
||||
[ImplementPropertyType(""foo"")]
|
||||
public virtual global::System.Collections.Generic.IEnumerable<global::" + modelsBuilderConfig.ModelsNamespace + @".Foo> Foo => this.Value<global::System.Collections.Generic.IEnumerable<global::" + modelsBuilderConfig.ModelsNamespace + @".Foo>>(_publishedValueFallback, ""foo"");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.16.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Include="System.Data.Odbc" Version="5.0.0" />
|
||||
<PackageReference Include="System.Data.OleDb" Version="5.0.0" />
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
var mgr = new BackOfficeCookieManager(
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
runtime,
|
||||
new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment()));
|
||||
new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment()),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/umbraco");
|
||||
|
||||
@@ -48,7 +49,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco")));
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco")),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/umbraco");
|
||||
|
||||
@@ -69,7 +71,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")));
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest(remainingTimeoutSecondsPath);
|
||||
Assert.IsTrue(result);
|
||||
@@ -90,7 +93,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")));
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/notbackoffice");
|
||||
Assert.IsFalse(result);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common.Extensions
|
||||
{
|
||||
[TestFixture]
|
||||
public class HttpContextExtensionTests
|
||||
{
|
||||
[Test]
|
||||
public void TryGetBasicAuthCredentials_WithoutHeader_ReturnsFalse()
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var result = httpContext.TryGetBasicAuthCredentials(out string _, out string _);
|
||||
|
||||
Assert.IsFalse(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetBasicAuthCredentials_WithHeader_ReturnsTrueWithCredentials()
|
||||
{
|
||||
const string Username = "fred";
|
||||
const string Password = "test";
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{Username}:{Password}"));
|
||||
httpContext.Request.Headers.Add("Authorization", $"Basic {credentials}");
|
||||
|
||||
bool result = httpContext.TryGetBasicAuthCredentials(out string username, out string password);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(Username, username);
|
||||
Assert.AreEqual(Password, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
|
||||
@@ -36,5 +37,15 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website
|
||||
Assert.AreEqual("~/Views/Template.cshtml", PathUtility.EnsurePathIsApplicationRootPrefixed("/Views/Template.cshtml"));
|
||||
Assert.AreEqual("~/Views/Template.cshtml", PathUtility.EnsurePathIsApplicationRootPrefixed("~/Views/Template.cshtml"));
|
||||
}
|
||||
|
||||
[AutoMoqData]
|
||||
[Test]
|
||||
public void EnsureApplicationMainUrl(AspNetCoreHostingEnvironment sut)
|
||||
{
|
||||
var url = new Uri("http://localhost:5000");
|
||||
sut.EnsureApplicationMainUrl(url);
|
||||
Assert.AreEqual(sut.ApplicationMainUrl, url);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,14 +56,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
|
||||
var content = Mock.Of<IReadOnlyContentBase>(x => x.ContentTypeId == 1);
|
||||
|
||||
var json = jsonSerializer.Serialize(content, cacheModel).StringData;
|
||||
var msgPack = msgPackSerializer.Serialize(content, cacheModel).ByteData;
|
||||
var json = jsonSerializer.Serialize(content, cacheModel, false).StringData;
|
||||
var msgPack = msgPackSerializer.Serialize(content, cacheModel, false).ByteData;
|
||||
|
||||
Console.WriteLine(json);
|
||||
Console.WriteLine(msgPackSerializer.ToJson(msgPack));
|
||||
|
||||
var jsonContent = jsonSerializer.Deserialize(content, json, null);
|
||||
var msgPackContent = msgPackSerializer.Deserialize(content, null, msgPack);
|
||||
var jsonContent = jsonSerializer.Deserialize(content, json, null, false);
|
||||
var msgPackContent = msgPackSerializer.Deserialize(content, null, msgPack, false);
|
||||
|
||||
|
||||
CollectionAssert.AreEqual(jsonContent.CultureData.Keys, msgPackContent.CultureData.Keys);
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -239,17 +238,25 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public Dictionary<string, Dictionary<string, string>> LocalizedText(string culture = null)
|
||||
public async Task<Dictionary<string, Dictionary<string, string>>> LocalizedText(string culture = null)
|
||||
{
|
||||
var isAuthenticated = _backofficeSecurityAccessor.BackOfficeSecurity.IsAuthenticated();
|
||||
CultureInfo cultureInfo;
|
||||
if (string.IsNullOrWhiteSpace(culture))
|
||||
{
|
||||
// Force authentication to occur since this is not an authorized endpoint, we need this to get a user.
|
||||
AuthenticateResult authenticationResult = await this.AuthenticateBackOfficeAsync();
|
||||
// We have to get the culture from the Identity, we can't rely on thread culture
|
||||
// It's entirely likely for a user to have a different culture in the backoffice, than their system.
|
||||
var user = authenticationResult.Principal?.Identity;
|
||||
|
||||
var cultureInfo = string.IsNullOrWhiteSpace(culture)
|
||||
//if the user is logged in, get their culture, otherwise default to 'en'
|
||||
? isAuthenticated
|
||||
//current culture is set at the very beginning of each request
|
||||
? Thread.CurrentThread.CurrentCulture
|
||||
: CultureInfo.GetCultureInfo(_globalSettings.DefaultUILanguage)
|
||||
: CultureInfo.GetCultureInfo(culture);
|
||||
cultureInfo = (authenticationResult.Succeeded && user is not null)
|
||||
? user.GetCulture()
|
||||
: CultureInfo.GetCultureInfo(_globalSettings.DefaultUILanguage);
|
||||
}
|
||||
else
|
||||
{
|
||||
cultureInfo = CultureInfo.GetCultureInfo(culture);
|
||||
}
|
||||
|
||||
var allValues = _textService.GetAllStoredValues(cultureInfo);
|
||||
var pathedValues = allValues.Select(kv =>
|
||||
|
||||
@@ -28,12 +28,9 @@ using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Web.BackOffice.ActionResults;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.BackOffice.ModelBinders;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
@@ -478,6 +475,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return result;
|
||||
}
|
||||
|
||||
private ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeysInternal(Guid[] contentTypeKeys, int parentId)
|
||||
{
|
||||
using var scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
var contentTypes = _contentTypeService.GetAll(contentTypeKeys).ToList();
|
||||
return GetEmpties(contentTypes, parentId).ToDictionary(x => x.ContentTypeKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of empty content items for all document types.
|
||||
/// </summary>
|
||||
@@ -486,9 +490,22 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[OutgoingEditorModelEvent]
|
||||
public ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeys([FromQuery] Guid[] contentTypeKeys, [FromQuery] int parentId)
|
||||
{
|
||||
using var scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
var contentTypes = _contentTypeService.GetAll(contentTypeKeys).ToList();
|
||||
return GetEmpties(contentTypes, parentId).ToDictionary(x => x.ContentTypeKey);
|
||||
return GetEmptyByKeysInternal(contentTypeKeys, parentId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of empty content items for all document types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a post request in order to support a large amount of GUIDs without hitting the URL length limit.
|
||||
/// </remarks>
|
||||
/// <param name="contentTypeByKeys"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[OutgoingEditorModelEvent]
|
||||
public ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeys(ContentTypesByKeys contentTypeByKeys)
|
||||
{
|
||||
return GetEmptyByKeysInternal(contentTypeByKeys.ContentTypeKeys, contentTypeByKeys.ParentId);
|
||||
}
|
||||
|
||||
[OutgoingEditorModelEvent]
|
||||
|
||||
@@ -21,7 +21,6 @@ using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Cms.Web.Common.Filters;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Extensions;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
|
||||
@@ -258,16 +258,16 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// <summary>
|
||||
/// Gets the URL of an entity
|
||||
/// </summary>
|
||||
/// <param name="udi">UDI of the entity to fetch URL for</param>
|
||||
/// <param name="id">UDI of the entity to fetch URL for</param>
|
||||
/// <param name="culture">The culture to fetch the URL for</param>
|
||||
/// <returns>The URL or path to the item</returns>
|
||||
public IActionResult GetUrl(Udi udi, string culture = "*")
|
||||
public IActionResult GetUrl(Udi id, string culture = "*")
|
||||
{
|
||||
var intId = _entityService.GetId(udi);
|
||||
var intId = _entityService.GetId(id);
|
||||
if (!intId.Success)
|
||||
return NotFound();
|
||||
UmbracoEntityTypes entityType;
|
||||
switch (udi.EntityType)
|
||||
switch (id.EntityType)
|
||||
{
|
||||
case Constants.UdiEntityType.Document:
|
||||
entityType = UmbracoEntityTypes.Document;
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Cms.Web.Common.Security;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
using Umbraco.Cms.Web.Common.Middleware;
|
||||
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
@@ -10,5 +12,6 @@ namespace Umbraco.Extensions
|
||||
|
||||
public static BackOfficeExternalLoginProviderErrors GetExternalLoginProviderErrors(this HttpContext httpContext)
|
||||
=> httpContext.Items[nameof(BackOfficeExternalLoginProviderErrors)] as BackOfficeExternalLoginProviderErrors;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Cms.Web.BackOffice.Middleware;
|
||||
using Umbraco.Cms.Web.BackOffice.Routing;
|
||||
using Umbraco.Cms.Web.Common.ApplicationBuilder;
|
||||
using Umbraco.Cms.Web.Common.Extensions;
|
||||
using Umbraco.Cms.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
|
||||
@@ -2,7 +2,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
@@ -23,6 +25,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly string[] _explicitPaths;
|
||||
private readonly UmbracoRequestPaths _umbracoRequestPaths;
|
||||
private readonly IBasicAuthService _basicAuthService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BackOfficeCookieManager"/> class.
|
||||
@@ -30,8 +33,9 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
public BackOfficeCookieManager(
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IRuntimeState runtime,
|
||||
UmbracoRequestPaths umbracoRequestPaths)
|
||||
: this(umbracoContextAccessor, runtime, null, umbracoRequestPaths)
|
||||
UmbracoRequestPaths umbracoRequestPaths,
|
||||
IBasicAuthService basicAuthService)
|
||||
: this(umbracoContextAccessor, runtime, null, umbracoRequestPaths, basicAuthService)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,12 +46,14 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IRuntimeState runtime,
|
||||
IEnumerable<string> explicitPaths,
|
||||
UmbracoRequestPaths umbracoRequestPaths)
|
||||
UmbracoRequestPaths umbracoRequestPaths,
|
||||
IBasicAuthService basicAuthService)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_runtime = runtime;
|
||||
_explicitPaths = explicitPaths?.ToArray();
|
||||
_umbracoRequestPaths = umbracoRequestPaths;
|
||||
_basicAuthService = basicAuthService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,6 +94,11 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_basicAuthService.IsBasicAuthEnabled())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
private readonly IIpResolver _ipResolver;
|
||||
private readonly ISystemClock _systemClock;
|
||||
private readonly UmbracoRequestPaths _umbracoRequestPaths;
|
||||
private readonly IBasicAuthService _basicAuthService;
|
||||
private readonly IOptionsMonitor<BasicAuthSettings> _optionsSnapshot;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigureBackOfficeCookieOptions"/> class.
|
||||
@@ -59,7 +61,8 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
IUserService userService,
|
||||
IIpResolver ipResolver,
|
||||
ISystemClock systemClock,
|
||||
UmbracoRequestPaths umbracoRequestPaths)
|
||||
UmbracoRequestPaths umbracoRequestPaths,
|
||||
IBasicAuthService basicAuthService)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
@@ -72,6 +75,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
_ipResolver = ipResolver;
|
||||
_systemClock = systemClock;
|
||||
_umbracoRequestPaths = umbracoRequestPaths;
|
||||
_basicAuthService = basicAuthService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -115,7 +119,9 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
options.CookieManager = new BackOfficeCookieManager(
|
||||
_umbracoContextAccessor,
|
||||
_runtimeState,
|
||||
_umbracoRequestPaths);
|
||||
_umbracoRequestPaths,
|
||||
_basicAuthService
|
||||
);
|
||||
|
||||
options.Events = new CookieAuthenticationEvents
|
||||
{
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Collections;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Extensions;
|
||||
@@ -13,7 +15,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetCoreHostingEnvironment : IHostingEnvironment
|
||||
{
|
||||
private readonly ISet<Uri> _applicationUrls = new HashSet<Uri>();
|
||||
private readonly ConcurrentHashSet<Uri> _applicationUrls = new ConcurrentHashSet<Uri>();
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IOptionsMonitor<HostingSettings> _hostingSettings;
|
||||
private readonly IOptionsMonitor<WebRoutingSettings> _webRoutingSettings;
|
||||
@@ -168,6 +170,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore
|
||||
// (this is a simplified version of what was in 7.x)
|
||||
// note: should this be optional? is it expensive?
|
||||
|
||||
|
||||
if (currentApplicationUrl is null)
|
||||
{
|
||||
return;
|
||||
@@ -181,9 +184,10 @@ namespace Umbraco.Cms.Web.Common.AspNetCore
|
||||
var change = !_applicationUrls.Contains(currentApplicationUrl);
|
||||
if (change)
|
||||
{
|
||||
_applicationUrls.Add(currentApplicationUrl);
|
||||
|
||||
ApplicationMainUrl = currentApplicationUrl;
|
||||
if (_applicationUrls.TryAdd(currentApplicationUrl))
|
||||
{
|
||||
ApplicationMainUrl = currentApplicationUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +101,10 @@ namespace Umbraco.Extensions
|
||||
services.AddSingleton(httpContextAccessor);
|
||||
|
||||
var requestCache = new HttpContextRequestAppCache(httpContextAccessor);
|
||||
var appCaches = AppCaches.Create(requestCache);
|
||||
var appCaches = AppCaches.Create(requestCache);
|
||||
|
||||
IProfiler profiler = GetWebProfiler(config);
|
||||
|
||||
|
||||
ILoggerFactory loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false));
|
||||
|
||||
TypeLoader typeLoader = services.AddTypeLoader(
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Umbraco.Extensions
|
||||
|
||||
IOptions<UmbracoPipelineOptions> startupOptions = app.ApplicationServices.GetRequiredService<IOptions<UmbracoPipelineOptions>>();
|
||||
app.RunPrePipeline(startupOptions.Value);
|
||||
|
||||
|
||||
app.UseUmbracoCore();
|
||||
app.UseUmbracoRequestLogging();
|
||||
|
||||
|
||||
@@ -14,13 +14,7 @@ namespace Umbraco.Extensions
|
||||
/// <returns></returns>
|
||||
public static async Task<AuthenticateResult> AuthenticateBackOfficeAsync(this ControllerBase controller)
|
||||
{
|
||||
if (controller.HttpContext == null)
|
||||
{
|
||||
return AuthenticateResult.NoResult();
|
||||
}
|
||||
|
||||
var result = await controller.HttpContext.AuthenticateAsync(Cms.Core.Constants.Security.BackOfficeAuthenticationType);
|
||||
return result;
|
||||
return await controller.HttpContext.AuthenticateBackOfficeAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
@@ -337,10 +337,14 @@ namespace Umbraco.Extensions
|
||||
);
|
||||
|
||||
|
||||
[Obsolete("Use GetCrop to merge local and media crops, get automatic cache buster value and have more parameters.")]
|
||||
public static string GetLocalCropUrl(
|
||||
this MediaWithCrops mediaWithCrops,
|
||||
string alias,
|
||||
string cacheBusterValue = null)
|
||||
=> mediaWithCrops.GetLocalCropUrl(alias, cacheBusterValue);
|
||||
{
|
||||
return mediaWithCrops.LocalCrops.Src +
|
||||
mediaWithCrops.LocalCrops.GetCropUrl(alias, ImageUrlGenerator, cacheBusterValue: cacheBusterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,60 @@
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class HttpContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Try to get the basic auth username and password from the http context.
|
||||
/// </summary>
|
||||
public static bool TryGetBasicAuthCredentials(this HttpContext httpContext, out string username, out string password)
|
||||
{
|
||||
username = null;
|
||||
password = null;
|
||||
|
||||
if (httpContext.Request.Headers.TryGetValue("Authorization", out StringValues authHeaders))
|
||||
{
|
||||
var authHeader = authHeaders.ToString();
|
||||
if (authHeader is not null && authHeader.StartsWith("Basic"))
|
||||
{
|
||||
// Extract credentials.
|
||||
var encodedUsernamePassword = authHeader.Substring(6).Trim();
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
var usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
|
||||
|
||||
var seperatorIndex = usernamePassword.IndexOf(':');
|
||||
|
||||
username = usernamePassword.Substring(0, seperatorIndex);
|
||||
password = usernamePassword.Substring(seperatorIndex + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the authentication process
|
||||
/// </summary>
|
||||
public static async Task<AuthenticateResult> AuthenticateBackOfficeAsync(this HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
return AuthenticateResult.NoResult();
|
||||
}
|
||||
|
||||
var result = await httpContext.AuthenticateAsync(Cms.Core.Constants.Security.BackOfficeAuthenticationType);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the value in the request form or query string for the key
|
||||
/// </summary>
|
||||
|
||||
@@ -7,7 +7,6 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
|
||||
@@ -217,9 +217,11 @@ namespace Umbraco.Extensions
|
||||
}
|
||||
|
||||
var url = mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
private static IHtmlContent CreateHtmlString(string url, bool htmlEncode) => htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
|
||||
public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias, bool htmlEncode = true)
|
||||
{
|
||||
if (mediaItem == null)
|
||||
@@ -228,7 +230,7 @@ namespace Umbraco.Extensions
|
||||
}
|
||||
|
||||
var url = mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper,
|
||||
@@ -256,7 +258,7 @@ namespace Umbraco.Extensions
|
||||
var url = mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
|
||||
upScale);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper,
|
||||
@@ -281,7 +283,7 @@ namespace Umbraco.Extensions
|
||||
var url = imageUrl.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
|
||||
upScale);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,9 +10,13 @@ namespace Umbraco.Cms.Web.Common.Security
|
||||
public sealed class ConfigureMemberIdentityOptions : IConfigureOptions<IdentityOptions>
|
||||
{
|
||||
private readonly MemberPasswordConfigurationSettings _memberPasswordConfiguration;
|
||||
private readonly SecuritySettings _securitySettings;
|
||||
|
||||
public ConfigureMemberIdentityOptions(IOptions<MemberPasswordConfigurationSettings> memberPasswordConfiguration)
|
||||
=> _memberPasswordConfiguration = memberPasswordConfiguration.Value;
|
||||
public ConfigureMemberIdentityOptions(IOptions<MemberPasswordConfigurationSettings> memberPasswordConfiguration, IOptions<SecuritySettings> securitySettings)
|
||||
{
|
||||
_memberPasswordConfiguration = memberPasswordConfiguration.Value;
|
||||
_securitySettings = securitySettings.Value;
|
||||
}
|
||||
|
||||
public void Configure(IdentityOptions options)
|
||||
{
|
||||
@@ -22,6 +26,9 @@ namespace Umbraco.Cms.Web.Common.Security
|
||||
|
||||
options.User.RequireUniqueEmail = true;
|
||||
|
||||
// Support validation of member names using Down-Level Logon Name format
|
||||
options.User.AllowedUserNameCharacters = _securitySettings.AllowedUserNameCharacters;
|
||||
|
||||
options.Lockout.AllowedForNewUsers = true;
|
||||
// TODO: Implement this
|
||||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromDays(30);
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
630
src/Umbraco.Web.UI.Client/package-lock.json
generated
630
src/Umbraco.Web.UI.Client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -126,7 +126,9 @@
|
||||
// close all editors
|
||||
if (args && !args.editor && args.editors.length === 0) {
|
||||
editorCount = 0;
|
||||
scope.editors = [];
|
||||
scope.editors = [];
|
||||
// Remove the inert attribute from the #mainwrapper
|
||||
focusLockService.removeInertAttribute();
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbImageCrop',
|
||||
function ($timeout, $window, cropperHelper) {
|
||||
function ($timeout, cropperHelper, windowResizeListener) {
|
||||
|
||||
const MAX_SCALE = 4;
|
||||
|
||||
@@ -26,7 +26,7 @@ angular.module("umbraco.directives")
|
||||
forceUpdate: '@?'
|
||||
},
|
||||
|
||||
link: function (scope, element, attrs, windowResizeListener) {
|
||||
link: function (scope, element, attrs) {
|
||||
|
||||
var unsubscribe = [];
|
||||
let sliderRef = null;
|
||||
@@ -72,7 +72,7 @@ angular.module("umbraco.directives")
|
||||
};
|
||||
|
||||
function updateSlider() {
|
||||
if(sliderRef) {
|
||||
if (sliderRef) {
|
||||
// Update slider range min/max
|
||||
sliderRef.noUiSlider.updateOptions({
|
||||
"range": {
|
||||
@@ -102,7 +102,7 @@ angular.module("umbraco.directives")
|
||||
// cross-browser wheel delta
|
||||
var delta = Math.max(-50, Math.min(50, (event.wheelDelta || -event.detail)));
|
||||
|
||||
if(sliderRef) {
|
||||
if (sliderRef) {
|
||||
var currentScale =sliderRef.noUiSlider.get();
|
||||
|
||||
var newScale = Math.min(Math.max(currentScale + delta*.001*scope.dimensions.image.ratio, scope.dimensions.scale.min), scope.dimensions.scale.max);
|
||||
@@ -127,8 +127,8 @@ angular.module("umbraco.directives")
|
||||
'left': (parseInt(scope.dimensions.margin.left, 10)) + 'px'
|
||||
}
|
||||
};
|
||||
updateStyles();
|
||||
|
||||
updateStyles();
|
||||
|
||||
//elements
|
||||
var $viewport = element.find(".viewport");
|
||||
@@ -138,11 +138,11 @@ angular.module("umbraco.directives")
|
||||
$overlay.bind("focus", function () {
|
||||
$overlay.bind("DOMMouseScroll mousewheel onmousewheel", onScroll);
|
||||
});
|
||||
|
||||
$overlay.bind("blur", function () {
|
||||
$overlay.unbind("DOMMouseScroll mousewheel onmousewheel", onScroll);
|
||||
});
|
||||
|
||||
|
||||
//default constraints for drag n drop
|
||||
var constraints = { left: { max: 0, min: 0 }, top: { max: 0, min: 0 } };
|
||||
scope.constraints = constraints;
|
||||
|
||||
@@ -57,7 +57,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* Do stuff...
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
@@ -691,11 +691,12 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
getScaffoldByKeys: function (parentId, scaffoldKeys) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetEmptyByKeys",
|
||||
{ contentTypeKeys: scaffoldKeys, parentId: parentId })),
|
||||
"GetEmptyByKeys"),
|
||||
{ contentTypeKeys: scaffoldKeys, parentId: parentId }
|
||||
),
|
||||
'Failed to retrieve data for empty content items ids' + scaffoldKeys.join(", "))
|
||||
.then(function (result) {
|
||||
Object.keys(result).map(function(key) {
|
||||
@@ -804,7 +805,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
|
||||
//converts the value to a js bool
|
||||
function toBool(v) {
|
||||
if (Utilities.isNumber(v)) {
|
||||
|
||||
@@ -142,7 +142,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetUrl",
|
||||
[{ udi: udi }, {culture: culture }])),
|
||||
[{ id: udi }, {culture: culture }])),
|
||||
'Failed to retrieve url for UDI:' + udi);
|
||||
},
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@
|
||||
* @returns {Object | null} Scaffold model for the that content type. Or null if the scaffolding model dosnt exist in this context.
|
||||
*/
|
||||
getScaffoldFromKey: function (contentTypeKey) {
|
||||
return this.scaffolds.find(o => o.contentTypeKey === contentTypeKey);
|
||||
return this.scaffolds.find(o => o.contentTypeKey === contentTypeKey) || null;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -499,7 +499,7 @@
|
||||
* @returns {Object | null} Scaffold model for the that content type. Or null if the scaffolding model dosnt exist in this context.
|
||||
*/
|
||||
getScaffoldFromAlias: function (contentTypeAlias) {
|
||||
return this.scaffolds.find(o => o.contentTypeAlias === contentTypeAlias);
|
||||
return this.scaffolds.find(o => o.contentTypeAlias === contentTypeAlias) || null;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -609,10 +609,14 @@
|
||||
blockObject.settingsData = settingsData;
|
||||
|
||||
// make basics from scaffold
|
||||
blockObject.settings = Utilities.copy(settingsScaffold);
|
||||
ensureUdiAndKey(blockObject.settings, settingsUdi);
|
||||
if (settingsScaffold !== null) {// We might not have settingsScaffold
|
||||
blockObject.settings = Utilities.copy(settingsScaffold);
|
||||
ensureUdiAndKey(blockObject.settings, settingsUdi);
|
||||
|
||||
mapToElementModel(blockObject.settings, settingsData);
|
||||
mapToElementModel(blockObject.settings, settingsData);
|
||||
} else {
|
||||
blockObject.settings = null;
|
||||
}
|
||||
|
||||
// add settings content-app
|
||||
appendSettingsContentApp(blockObject.content, this.__labels.settingsName);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
angular.module('umbraco.services')
|
||||
.factory('localizationService', function ($http, $q, eventsService, $window, $filter, userService) {
|
||||
.factory('localizationService', function ($http, $q, eventsService) {
|
||||
|
||||
// TODO: This should be injected as server vars
|
||||
var url = "LocalizedText";
|
||||
@@ -61,14 +61,14 @@ angular.module('umbraco.services')
|
||||
|
||||
return "[" + alias + "]";
|
||||
}
|
||||
|
||||
|
||||
var service = {
|
||||
|
||||
|
||||
|
||||
// loads the language resource file from the server
|
||||
initLocalizedResources: function () {
|
||||
|
||||
// TODO: This promise handling is super ugly, we should just be returnning the promise from $http and returning inner values.
|
||||
// TODO: This promise handling is super ugly, we should just be returnning the promise from $http and returning inner values.
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
@@ -120,7 +120,7 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Helper to tokenize and compile a localization string
|
||||
* @param {String} value the value to tokenize
|
||||
* @param {Object} scope the $scope object
|
||||
* @param {Object} scope the $scope object
|
||||
* @returns {String} tokenized resource string
|
||||
*/
|
||||
tokenize: function (value, scope) {
|
||||
@@ -138,8 +138,8 @@ angular.module('umbraco.services')
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.localizationService#tokenReplace
|
||||
@@ -148,19 +148,19 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Helper to replace tokens
|
||||
* @param {String} value the text-string to manipulate
|
||||
* @param {Array} tekens An array of tokens values
|
||||
* @param {Array} tekens An array of tokens values
|
||||
* @returns {String} Replaced test-string
|
||||
*/
|
||||
tokenReplace: function (text, tokens) {
|
||||
if (tokens) {
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
text = text.replace("%" + i + "%", tokens[i]);
|
||||
text = text.replace("%" + i + "%", _.escape(tokens[i]));
|
||||
}
|
||||
}
|
||||
return text;
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.localizationService#localize
|
||||
@@ -168,16 +168,16 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @description
|
||||
* Checks the dictionary for a localized resource string
|
||||
* @param {String} value the area/key to localize in the format of 'section_key'
|
||||
* @param {String} value the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @param {Array} tokens if specified this array will be sent as parameter values
|
||||
* This replaces %0% and %1% etc in the dictionary key value with the passed in strings
|
||||
*
|
||||
* @param {String} fallbackValue if specified this string will be returned if no matching
|
||||
*
|
||||
* @param {String} fallbackValue if specified this string will be returned if no matching
|
||||
* entry was found in the dictionary
|
||||
*
|
||||
*
|
||||
* @returns {String} localized resource string
|
||||
*/
|
||||
localize: function (value, tokens, fallbackValue) {
|
||||
@@ -194,7 +194,7 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Checks the dictionary for multipe localized resource strings at once, preventing the need for nested promises
|
||||
* with localizationService.localize
|
||||
*
|
||||
*
|
||||
* ##Usage
|
||||
* <pre>
|
||||
* localizationService.localizeMany(["speechBubbles_templateErrorHeader", "speechBubbles_templateErrorText"]).then(function(data){
|
||||
@@ -203,11 +203,11 @@ angular.module('umbraco.services')
|
||||
* notificationService.error(header, message);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @returns {Array} An array of localized resource string in the same order
|
||||
*/
|
||||
localizeMany: function(keys) {
|
||||
@@ -234,18 +234,18 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Checks the dictionary for multipe localized resource strings at once & concats them to a single string
|
||||
* Which was not possible with localizationSerivce.localize() due to returning a promise
|
||||
*
|
||||
*
|
||||
* ##Usage
|
||||
* <pre>
|
||||
* localizationService.concat(["speechBubbles_templateErrorHeader", "speechBubbles_templateErrorText"]).then(function(data){
|
||||
* var combinedText = data;
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @returns {String} An concatenated string of localized resource string passed into the function in the same order
|
||||
*/
|
||||
concat: function(keys) {
|
||||
@@ -280,7 +280,7 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Checks the dictionary for multipe localized resource strings at once & formats a tokenized message
|
||||
* Which was not possible with localizationSerivce.localize() due to returning a promise
|
||||
*
|
||||
*
|
||||
* ##Usage
|
||||
* <pre>
|
||||
* localizationService.format(["template_insert", "template_insertSections"], "%0% %1%").then(function(data){
|
||||
@@ -288,14 +288,14 @@ angular.module('umbraco.services')
|
||||
* var formattedResult = data;
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @param {String} message is the string you wish to replace containing tokens in the format of %0% and %1%
|
||||
* with the localized resource strings
|
||||
*
|
||||
*
|
||||
* @returns {String} An concatenated string of localized resource string passed into the function in the same order
|
||||
*/
|
||||
format: function(keys, message){
|
||||
@@ -330,7 +330,7 @@ angular.module('umbraco.services')
|
||||
resourceFileLoadStatus = "none";
|
||||
resourceLoadingPromise = [];
|
||||
});
|
||||
|
||||
|
||||
|
||||
// return the local instance when called
|
||||
return service;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
function windowResizeListener($rootScope) {
|
||||
|
||||
var WinReszier = (function () {
|
||||
var WinResizer = (function () {
|
||||
var registered = [];
|
||||
var inited = false;
|
||||
var resize = _.debounce(function(ev) {
|
||||
@@ -51,7 +51,7 @@ function windowResizeListener($rootScope) {
|
||||
* @param {Function} cb
|
||||
*/
|
||||
register: function (cb) {
|
||||
WinReszier.register(cb);
|
||||
WinResizer.register(cb);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -59,9 +59,9 @@ function windowResizeListener($rootScope) {
|
||||
* @param {Function} cb
|
||||
*/
|
||||
unregister: function(cb) {
|
||||
WinReszier.unregister(cb);
|
||||
WinResizer.unregister(cb);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.services').factory('windowResizeListener', windowResizeListener);
|
||||
angular.module('umbraco.services').factory('windowResizeListener', windowResizeListener);
|
||||
|
||||
@@ -154,9 +154,10 @@
|
||||
currentForm.$dirty = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.dialog.confirmDiscardChanges = false;
|
||||
vm.saveState = "success";
|
||||
vm.saveSuccces = true;
|
||||
|
||||
}, function(error){
|
||||
vm.saveState = "error";
|
||||
vm.saveError = error;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user