Merge remote-tracking branch 'origin/netcore/netcore' into netcore/task/front-end-routing

# Conflicts:
#	src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
#	src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs
#	src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs
This commit is contained in:
Shannon
2020-12-21 16:04:42 +11:00
95 changed files with 1550 additions and 1516 deletions

View File

@@ -18,7 +18,7 @@ namespace Umbraco.Core
/// <remarks>
/// This is not the same as the Umbraco web folder which is configurable for serving front-end files.
/// </remarks>
public const string Umbraco = "~/Umbraco";
public const string Umbraco = "~/umbraco";
/// <summary>
/// The Umbraco data folder in the content root

View File

@@ -1,6 +1,7 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Core.Events;
@@ -26,5 +27,22 @@ namespace Umbraco.Core.DependencyInjection
builder.Services.AddTransient(typeof(INotificationHandler<TNotification>), typeof(TNotificationHandler));
return builder;
}
/// <summary>
/// Registers a notification handler against the Umbraco service collection.
/// </summary>
/// <typeparam name="TNotification">The type of notification.</typeparam>
/// <typeparam name="TNotificationHandler">The type of notificiation handler.</typeparam>
/// <param name="builder">The Umbraco builder.</param>
/// <param name="factory">Factory method</param>
/// <returns>The <see cref="IUmbracoBuilder"/>.</returns>
public static IUmbracoBuilder AddNotificationHandler<TNotification, TNotificationHandler>(this IUmbracoBuilder builder, Func<IServiceProvider, TNotificationHandler> factory)
where TNotificationHandler : class, INotificationHandler<TNotification>
where TNotification : INotification
{
// Register the handler as transient. This ensures that anything can be injected into it.
builder.Services.AddTransient(typeof(INotificationHandler<TNotification>), factory);
return builder;
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Umbraco.Core.Events
{
public class UmbracoApplicationStarting : INotification
{
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoApplicationStarting"/> class.
/// </summary>
/// <param name="runtimeLevel">The runtime level</param>
public UmbracoApplicationStarting(RuntimeLevel runtimeLevel) => RuntimeLevel = runtimeLevel;
/// <summary>
/// Gets the runtime level of execution.
/// </summary>
public RuntimeLevel RuntimeLevel { get; }
}
}

View File

@@ -0,0 +1,4 @@
namespace Umbraco.Core.Events
{
public class UmbracoApplicationStopping : INotification { }
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Umbraco.Core.Models.Packaging
@@ -40,6 +39,8 @@ namespace Umbraco.Core.Models.Packaging
public IEnumerable<XElement> Languages { get; set; } // TODO: make strongly typed
public IEnumerable<XElement> DictionaryItems { get; set; } // TODO: make strongly typed
public IEnumerable<XElement> DocumentTypes { get; set; } // TODO: make strongly typed
public IEnumerable<CompiledPackageDocument> Documents { get; set; }
public IEnumerable<XElement> MediaTypes { get; set; } // TODO: make strongly typed
public IEnumerable<CompiledPackageContentBase> Documents { get; set; }
public IEnumerable<CompiledPackageContentBase> Media { get; set; }
}
}

View File

@@ -1,20 +1,18 @@
using System;
using System.Xml.Linq;
namespace Umbraco.Core.Models.Packaging
{
public class CompiledPackageDocument
/// <summary>
/// Compiled representation of a content base (Document or Media)
/// </summary>
public class CompiledPackageContentBase
{
public static CompiledPackageDocument Create(XElement xml)
{
if (xml.Name.LocalName != "DocumentSet")
throw new ArgumentException("The xml isn't formatted correctly, a document element is defined by <DocumentSet>", nameof(xml));
return new CompiledPackageDocument
public static CompiledPackageContentBase Create(XElement xml) =>
new CompiledPackageContentBase
{
XmlData = xml,
ImportMode = xml.AttributeValue<string>("importMode")
};
}
public string ImportMode { get; set; } //this is never used
@@ -23,4 +21,4 @@ namespace Umbraco.Core.Models.Packaging
/// </summary>
public XElement XmlData { get; set; }
}
}
}

View File

@@ -6,7 +6,6 @@ using System.Xml.Linq;
using Microsoft.Extensions.Options;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Models.Packaging;
using File = System.IO.File;
namespace Umbraco.Core.Packaging
{
@@ -64,7 +63,9 @@ namespace Umbraco.Core.Packaging
Languages = xml.Root.Element("Languages")?.Elements("Language") ?? Enumerable.Empty<XElement>(),
DictionaryItems = xml.Root.Element("DictionaryItems")?.Elements("DictionaryItem") ?? Enumerable.Empty<XElement>(),
DocumentTypes = xml.Root.Element("DocumentTypes")?.Elements("DocumentType") ?? Enumerable.Empty<XElement>(),
Documents = xml.Root.Element("Documents")?.Elements("DocumentSet")?.Select(CompiledPackageDocument.Create) ?? Enumerable.Empty<CompiledPackageDocument>(),
MediaTypes = xml.Root.Element("MediaTypes")?.Elements("MediaType") ?? Enumerable.Empty<XElement>(),
Documents = xml.Root.Element("Documents")?.Elements("DocumentSet")?.Select(CompiledPackageContentBase.Create) ?? Enumerable.Empty<CompiledPackageContentBase>(),
Media = xml.Root.Element("MediaItems")?.Elements()?.Select(CompiledPackageContentBase.Create) ?? Enumerable.Empty<CompiledPackageContentBase>(),
};
def.Warnings = GetPreInstallWarnings(def, applicationRootFolder);

View File

@@ -17,11 +17,13 @@ namespace Umbraco.Core.Models.Packaging
public IEnumerable<string> FilesInstalled { get; set; } = Enumerable.Empty<string>();
public IEnumerable<ITemplate> TemplatesInstalled { get; set; } = Enumerable.Empty<ITemplate>();
public IEnumerable<IContentType> DocumentTypesInstalled { get; set; } = Enumerable.Empty<IContentType>();
public IEnumerable<IMediaType> MediaTypesInstalled { get; set; } = Enumerable.Empty<IMediaType>();
public IEnumerable<IFile> StylesheetsInstalled { get; set; } = Enumerable.Empty<IFile>();
public IEnumerable<IContent> ContentInstalled { get; set; } = Enumerable.Empty<IContent>();
public IEnumerable<IMedia> MediaInstalled { get; set; } = Enumerable.Empty<IMedia>();
public IEnumerable<PackageAction> Actions { get; set; } = Enumerable.Empty<PackageAction>();
public IEnumerable<string> ActionErrors { get; set; } = Enumerable.Empty<string>();
}
}

View File

@@ -4,7 +4,6 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Models.Packaging
{
@@ -114,6 +113,9 @@ namespace Umbraco.Core.Models.Packaging
[DataMember(Name = "documentTypes")]
public IList<string> DocumentTypes { get; set; } = new List<string>();
[DataMember(Name = "mediaTypes")]
public IList<string> MediaTypes { get; set; } = new List<string>();
[DataMember(Name = "stylesheets")]
public IList<string> Stylesheets { get; set; } = new List<string>();
@@ -133,6 +135,12 @@ namespace Umbraco.Core.Models.Packaging
[DataMember(Name = "iconUrl")]
public string IconUrl { get; set; } = string.Empty;
[DataMember(Name = "mediaUdis")]
public IList<GuidUdi> MediaUdis { get; set; } = Array.Empty<GuidUdi>();
[DataMember(Name = "mediaLoadChildNodes")]
public bool MediaLoadChildNodes { get; set; }
}

View File

@@ -46,10 +46,13 @@ namespace Umbraco.Core.Packaging
Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? "<actions></actions>", //take the entire outer xml value
ContentNodeId = xml.Element("content")?.AttributeValue<string>("nodeId") ?? string.Empty,
ContentLoadChildNodes = xml.Element("content")?.AttributeValue<bool>("loadChildNodes") ?? false,
MediaUdis = xml.Element("media")?.Elements("nodeUdi").Select(x => (GuidUdi)UdiParser.Parse(x.Value)).ToList() ?? new List<GuidUdi>(),
MediaLoadChildNodes = xml.Element("media")?.AttributeValue<bool>("loadChildNodes") ?? false,
Macros = xml.Element("macros")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
Templates = xml.Element("templates")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
Stylesheets = xml.Element("stylesheets")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
DocumentTypes = xml.Element("documentTypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
MediaTypes = xml.Element("mediaTypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
Languages = xml.Element("languages")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
DataTypes = xml.Element("datatypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
@@ -103,11 +106,17 @@ namespace Umbraco.Core.Packaging
new XElement("templates", string.Join(",", def.Templates ?? Array.Empty<string>())),
new XElement("stylesheets", string.Join(",", def.Stylesheets ?? Array.Empty<string>())),
new XElement("documentTypes", string.Join(",", def.DocumentTypes ?? Array.Empty<string>())),
new XElement("mediaTypes", string.Join(",", def.MediaTypes ?? Array.Empty<string>())),
new XElement("macros", string.Join(",", def.Macros ?? Array.Empty<string>())),
new XElement("files", (def.Files ?? Array.Empty<string>()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))),
new XElement("languages", string.Join(",", def.Languages ?? Array.Empty<string>())),
new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty<string>())));
new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty<string>())),
new XElement(
"media",
def.MediaUdis.Select(x=> (object)new XElement("nodeUdi", x))
.Union(new []{new XAttribute("loadChildNodes", def.MediaLoadChildNodes) }))
);
return packageXml;
}

View File

@@ -5,8 +5,8 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
@@ -38,6 +38,8 @@ namespace Umbraco.Core.Packaging
private readonly string _tempFolderPath;
private readonly PackageDefinitionXmlParser _parser;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IMediaService _mediaService;
private readonly IMediaTypeService _mediaTypeService;
/// <summary>
/// Constructor
@@ -65,6 +67,8 @@ namespace Umbraco.Core.Packaging
ILoggerFactory loggerFactory,
IUmbracoVersion umbracoVersion,
IOptions<GlobalSettings> globalSettings,
IMediaService mediaService,
IMediaTypeService mediaTypeService,
string packageRepositoryFileName,
string tempFolderPath = null, string packagesFolderPath = null, string mediaFolderPath = null)
{
@@ -87,6 +91,8 @@ namespace Umbraco.Core.Packaging
_parser = new PackageDefinitionXmlParser(_loggerFactory.CreateLogger<PackageDefinitionXmlParser>(), umbracoVersion);
_umbracoVersion = umbracoVersion;
_mediaService = mediaService;
_mediaTypeService = mediaTypeService;
}
private string CreatedPackagesFile => _packagesFolderPath.EnsureEndsWith('/') + _packageRepositoryFileName;
@@ -181,12 +187,15 @@ namespace Umbraco.Core.Packaging
PackageDocumentsAndTags(definition, root);
PackageDocumentTypes(definition, root);
PackageMediaTypes(definition, root);
PackageTemplates(definition, root);
PackageStylesheets(definition, root);
PackageMacros(definition, root, filesXml, temporaryPath);
PackageDictionaryItems(definition, root);
PackageLanguages(definition, root);
PackageDataTypes(definition, root);
PackageMedia(definition, root);
// TODO: This needs to be split into content vs web files, for now we are going to
// assume all files are web (www) files. But this is a larger discussion/change since
@@ -194,13 +203,13 @@ namespace Umbraco.Core.Packaging
//Files
foreach (var fileName in definition.Files)
AppendFileToPackage(fileName, temporaryPath, filesXml, true);
AppendFileToPackage(fileName, temporaryPath, filesXml);
//Load view on install...
if (!string.IsNullOrEmpty(definition.PackageView))
{
var control = new XElement("view", definition.PackageView);
AppendFileToPackage(definition.PackageView, temporaryPath, filesXml, true);
AppendFileToPackage(definition.PackageView, temporaryPath, filesXml);
root.Add(control);
}
@@ -310,7 +319,7 @@ namespace Umbraco.Core.Packaging
macros.Add(macroXml);
//if the macro has a file copy it to the xml
if (!string.IsNullOrEmpty(macro.MacroSource))
AppendFileToPackage(macro.MacroSource, temporaryPath, filesXml, false);
AppendFileToPackage(macro.MacroSource, temporaryPath, filesXml);
}
root.Add(macros);
}
@@ -358,6 +367,23 @@ namespace Umbraco.Core.Packaging
root.Add(docTypesXml);
}
private void PackageMediaTypes(PackageDefinition definition, XContainer root)
{
var mediaTypes = new HashSet<IMediaType>();
var mediaTypesXml = new XElement("MediaTypes");
foreach (var mediaTypeId in definition.MediaTypes)
{
if (!int.TryParse(mediaTypeId, out var outInt)) continue;
var mediaType = _mediaTypeService.Get(outInt);
if (mediaType == null) continue;
AddMediaType(mediaType, mediaTypes);
}
foreach (var mediaType in mediaTypes)
mediaTypesXml.Add(_serializer.Serialize(mediaType));
root.Add(mediaTypesXml);
}
private void PackageDocumentsAndTags(PackageDefinition definition, XContainer root)
{
//Documents and tags
@@ -442,6 +468,18 @@ namespace Umbraco.Core.Packaging
}
}
private void PackageMedia(PackageDefinition definition, XElement root)
{
IEnumerable<IMedia> medias = _mediaService.GetByIds(definition.MediaUdis);
root.Add(
new XElement(
"MediaItems",
medias.Select(x => new XElement("MediaSet", _serializer.Serialize(x, definition.MediaLoadChildNodes)))));
}
/// <summary>
/// Zips the package.
/// </summary>
@@ -461,12 +499,12 @@ namespace Umbraco.Core.Packaging
/// <param name="packageDirectory">The package directory.</param>
/// <param name="filesXml">The files xml node</param>
/// <param name="isWebFile">true if it's a web file, false if it's a content file</param>
private void AppendFileToPackage(string path, string packageDirectory, XContainer filesXml, bool isWebFile)
private void AppendFileToPackage(string path, string packageDirectory, XContainer filesXml)
{
if (!path.StartsWith("~/") && !path.StartsWith("/"))
path = "~/" + path;
var serverPath = isWebFile ? _hostingEnvironment.MapPathWebRoot(path) : _hostingEnvironment.MapPathContentRoot(path);
var serverPath = _hostingEnvironment.MapPathContentRoot(path);
if (File.Exists(serverPath))
AppendFileXml(new FileInfo(serverPath), path, packageDirectory, filesXml);
@@ -562,6 +600,19 @@ namespace Umbraco.Core.Packaging
dtl.Add(dt);
}
private void AddMediaType(IMediaType mediaType, HashSet<IMediaType> mediaTypes)
{
if (mediaType.ParentId > 0)
{
var parent = _mediaTypeService.Get(mediaType.ParentId);
if (parent != null) // could be a container
AddMediaType(parent, mediaTypes);
}
if (!mediaTypes.Contains(mediaType))
mediaTypes.Add(mediaType);
}
private static XElement GetPackageInfoXml(PackageDefinition definition, IUmbracoVersion umbracoVersion)
{

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Querying;
@@ -10,7 +9,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Defines the ContentService, which is an easy access to operations involving <see cref="IContent"/>
/// </summary>
public interface IContentService : IContentServiceBase
public interface IContentService : IContentServiceBase<IContent>
{
#region Blueprints

View File

@@ -1,7 +1,16 @@
using Umbraco.Core.Models;
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Services
{
public interface IContentServiceBase<TItem> : IContentServiceBase
where TItem: class, IContentBase
{
TItem GetById(Guid key);
Attempt<OperationResult> Save(IEnumerable<TItem> contents, int userId = Constants.Security.SuperUserId, bool raiseEvents = true);
}
/// <summary>
/// Placeholder for sharing logic between the content, media (and member) services
/// TODO: Start sharing the logic!

View File

@@ -58,7 +58,6 @@ namespace Umbraco.Core.Services
void Save(TItem item, int userId = Constants.Security.SuperUserId);
void Save(IEnumerable<TItem> items, int userId = Constants.Security.SuperUserId);
void Delete(TItem item, int userId = Constants.Security.SuperUserId);
void Delete(IEnumerable<TItem> item, int userId = Constants.Security.SuperUserId);

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Querying;
@@ -10,7 +9,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Defines the Media Service, which is an easy access to operations involving <see cref="IMedia"/>
/// </summary>
public interface IMediaService : IContentServiceBase
public interface IMediaService : IContentServiceBase<IMedia>
{
int CountNotTrashed(string contentTypeAlias = null);
int Count(string mediaTypeAlias = null);

View File

@@ -1,22 +1,15 @@
using System;
using Microsoft.Extensions.Hosting;
namespace Umbraco.Core
{
/// <summary>
/// Defines the Umbraco runtime.
/// </summary>
public interface IRuntime
public interface IRuntime : IHostedService
{
/// <summary>
/// Gets the runtime state.
/// </summary>
IRuntimeState State { get; }
void Start();
/// <summary>
/// Terminates the runtime.
/// </summary>
void Terminate();
}
}

View File

@@ -16,6 +16,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.8" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />

View File

@@ -1,51 +0,0 @@
using System.IO;
using Microsoft.Extensions.Logging;
using Umbraco.Core.Composing;
using Umbraco.Core.Hosting;
using Umbraco.Core.Manifest;
using Umbraco.Net;
namespace Umbraco.Core.Compose
{
public sealed class ManifestWatcherComponent : IComponent
{
private readonly IHostingEnvironment _hosting;
private readonly ILoggerFactory _loggerFactory;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
// if configured and in debug mode, a ManifestWatcher watches App_Plugins folders for
// package.manifest chances and restarts the application on any change
private ManifestWatcher _mw;
public ManifestWatcherComponent(IHostingEnvironment hosting, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IUmbracoApplicationLifetime umbracoApplicationLifetime)
{
_hosting = hosting;
_loggerFactory = loggerFactory;
_hostingEnvironment = hostingEnvironment;
_umbracoApplicationLifetime = umbracoApplicationLifetime;
}
public void Initialize()
{
if (_hosting.IsDebugMode == false) return;
//if (ApplicationContext.Current.IsConfigured == false || GlobalSettings.DebugMode == false)
// return;
var appPlugins = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins);
if (Directory.Exists(appPlugins) == false) return;
_mw = new ManifestWatcher(_loggerFactory.CreateLogger<ManifestWatcher>(), _umbracoApplicationLifetime);
_mw.Start(Directory.GetDirectories(appPlugins));
}
public void Terminate()
{
if (_mw == null) return;
_mw.Dispose();
_mw = null;
}
}
}

View File

@@ -1,7 +0,0 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Compose
{
public class ManifestWatcherComposer : ComponentComposer<ManifestWatcherComponent>, ICoreComposer
{ }
}

View File

@@ -2,15 +2,14 @@
using System.IO;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Umbraco.Core.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.DependencyInjection;
using Umbraco.Core.Events;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Packaging;
using Umbraco.Core.Routing;
using Umbraco.Core.Services;
@@ -99,6 +98,8 @@ namespace Umbraco.Core.Composing.CompositionExtensions
factory.GetRequiredService<ILoggerFactory>(),
factory.GetRequiredService<IUmbracoVersion>(),
factory.GetRequiredService<IOptions<GlobalSettings>>(),
factory.GetRequiredService<IMediaService>(),
factory.GetRequiredService<IMediaTypeService>(),
packageRepoFileName);
private static LocalizedTextServiceFileSources SourcesFactory(IServiceProvider container)

View File

@@ -1,20 +0,0 @@
using Microsoft.Extensions.Hosting;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Extends the <see cref="IHostBuilder"/> to enable Umbraco to be used as the service container.
/// </summary>
public static class HostBuilderExtensions
{
/// <summary>
/// Assigns a custom service provider factory to use Umbraco's container
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IHostBuilder UseUmbraco(this IHostBuilder builder)
{
return builder;
}
}
}

View File

@@ -34,15 +34,32 @@ namespace Umbraco.Core.Packaging
private readonly GlobalSettings _globalSettings;
private readonly ILocalizedTextService _localizedTextService;
private readonly IConfigurationEditorJsonSerializer _serializer;
private readonly IMediaService _mediaService;
private readonly IMediaTypeService _mediaTypeService;
private readonly IJsonSerializer _jsonSerializer;
private readonly IEntityService _entityService;
private readonly IContentTypeService _contentTypeService;
private readonly IContentService _contentService;
public PackageDataInstallation(ILogger<PackageDataInstallation> logger, ILoggerFactory loggerFactory, IFileService fileService, IMacroService macroService, ILocalizationService localizationService,
IDataTypeService dataTypeService, IEntityService entityService, IContentTypeService contentTypeService,
IContentService contentService, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IShortStringHelper shortStringHelper, IOptions<GlobalSettings> globalSettings,
ILocalizedTextService localizedTextService, IConfigurationEditorJsonSerializer serializer, IJsonSerializer jsonSerializer)
public PackageDataInstallation(
ILogger<PackageDataInstallation> logger,
ILoggerFactory loggerFactory,
IFileService fileService,
IMacroService macroService,
ILocalizationService localizationService,
IDataTypeService dataTypeService,
IEntityService entityService,
IContentTypeService contentTypeService,
IContentService contentService,
PropertyEditorCollection propertyEditors,
IScopeProvider scopeProvider,
IShortStringHelper shortStringHelper,
IOptions<GlobalSettings> globalSettings,
ILocalizedTextService localizedTextService,
IConfigurationEditorJsonSerializer serializer,
IMediaService mediaService,
IMediaTypeService mediaTypeService,
IJsonSerializer jsonSerializer)
{
_logger = logger;
_loggerFactory = loggerFactory;
@@ -57,6 +74,8 @@ namespace Umbraco.Core.Packaging
_localizedTextService = localizedTextService;
_serializer = serializer;
_jsonSerializer = jsonSerializer;
_mediaService = mediaService;
_mediaTypeService = mediaTypeService;
_entityService = entityService;
_contentTypeService = contentTypeService;
_contentService = contentService;
@@ -197,29 +216,58 @@ namespace Umbraco.Core.Packaging
DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId),
MacrosInstalled = ImportMacros(compiledPackage.Macros, userId),
TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId),
DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId)
DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId),
MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId),
};
//we need a reference to the imported doc types to continue
var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x);
var importedMediaTypes = installationSummary.MediaTypesInstalled.ToDictionary(x => x.Alias, x => x);
installationSummary.StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId);
installationSummary.ContentInstalled = ImportContent(compiledPackage.Documents, importedDocTypes, userId);
installationSummary.ContentInstalled = ImportContentBase(compiledPackage.Documents, importedDocTypes, userId, _contentTypeService, _contentService);
installationSummary.MediaInstalled = ImportContentBase(compiledPackage.Media, importedMediaTypes, userId, _mediaTypeService, _mediaService);
scope.Complete();
return installationSummary;
}
}
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="docTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IMediaType> ImportMediaTypes(IEnumerable<XElement> docTypeElements, int userId)
{
return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService);
}
#endregion
#region Content
public IReadOnlyList<IContent> ImportContent(IEnumerable<CompiledPackageDocument> docs, IDictionary<string, IContentType> importedDocumentTypes, int userId)
public IReadOnlyList<T> ImportContentBase<T, S>(
IEnumerable<CompiledPackageContentBase> docs,
IDictionary<string, S> importedDocumentTypes,
int userId,
IContentTypeBaseService<S> typeService,
IContentServiceBase<T> service)
where T: class, IContentBase
where S: IContentTypeComposition
{
return docs.SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId)).ToList();
return docs.SelectMany(x => ImportContentBase<T, S>(
x.XmlData.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty),
-1,
importedDocumentTypes,
userId,
typeService,
service)).ToList();
}
/// <summary>
@@ -230,17 +278,20 @@ namespace Umbraco.Core.Packaging
/// <param name="importedDocumentTypes">A dictionary of already imported document types (basically used as a cache)</param>
/// <param name="userId">Optional Id of the user performing the import</param>
/// <returns>An enumerable list of generated content</returns>
public IEnumerable<IContent> ImportContent(CompiledPackageDocument packageDocument, int parentId, IDictionary<string, IContentType> importedDocumentTypes, int userId)
public IEnumerable<T> ImportContentBase<T, S>(
IEnumerable<XElement> roots,
int parentId,
IDictionary<string, S> importedDocumentTypes,
int userId,
IContentTypeBaseService<S> typeService,
IContentServiceBase<T> service)
where T: class, IContentBase
where S: IContentTypeComposition
{
var element = packageDocument.XmlData;
var roots = from doc in element.Elements()
where (string)doc.Attribute("isDoc") == ""
select doc;
var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList();
var contents = ParseContentBaseRootXml(roots, parentId, importedDocumentTypes, typeService, service).ToList();
if (contents.Any())
_contentService.Save(contents, userId);
service.Save(contents, userId);
return contents;
@@ -249,7 +300,7 @@ namespace Umbraco.Core.Packaging
//{
// //This is a single doc import
// var elements = new List<XElement> { element };
// var contents = ParseDocumentRootXml(elements, parentId, importedDocumentTypes).ToList();
// var contents = ParseContentBaseRootXml(elements, parentId, importedDocumentTypes).ToList();
// if (contents.Any())
// _contentService.Save(contents, userId);
@@ -261,50 +312,64 @@ namespace Umbraco.Core.Packaging
// "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import).");
}
private IEnumerable<IContent> ParseDocumentRootXml(IEnumerable<XElement> roots, int parentId, IDictionary<string, IContentType> importedContentTypes)
private IEnumerable<T> ParseContentBaseRootXml<T, S>(
IEnumerable<XElement> roots,
int parentId,
IDictionary<string, S> importedContentTypes,
IContentTypeBaseService<S> typeService,
IContentServiceBase<T> service)
where T: class, IContentBase
where S: IContentTypeComposition
{
var contents = new List<IContent>();
var contents = new List<T>();
foreach (var root in roots)
{
var contentTypeAlias = root.Name.LocalName;
if (!importedContentTypes.ContainsKey(contentTypeAlias))
{
var contentType = FindContentTypeByAlias(contentTypeAlias);
var contentType = FindContentTypeByAlias(contentTypeAlias, typeService);
importedContentTypes.Add(contentTypeAlias, contentType);
}
var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], null, parentId);
var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], default(T), parentId, service);
if (content == null) continue;
contents.Add(content);
var children = (from child in root.Elements()
where (string)child.Attribute("isDoc") == ""
select child)
var children = root.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty)
.ToList();
if (children.Count > 0)
contents.AddRange(CreateContentFromXml(children, content, importedContentTypes).WhereNotNull());
{
contents.AddRange(CreateContentFromXml<T, S>(children, content, importedContentTypes, typeService, service).WhereNotNull());
}
}
return contents;
}
private IEnumerable<IContent> CreateContentFromXml(IEnumerable<XElement> children, IContent parent, IDictionary<string, IContentType> importedContentTypes)
private IEnumerable<T> CreateContentFromXml<T, S>(
IEnumerable<XElement> children,
T parent,
IDictionary<string, S> importedContentTypes,
IContentTypeBaseService<S> typeService,
IContentServiceBase<T> service)
where T: class, IContentBase
where S: IContentTypeComposition
{
var list = new List<IContent>();
var list = new List<T>();
foreach (var child in children)
{
string contentTypeAlias = child.Name.LocalName;
if (importedContentTypes.ContainsKey(contentTypeAlias) == false)
{
var contentType = FindContentTypeByAlias(contentTypeAlias);
var contentType = FindContentTypeByAlias(contentTypeAlias, typeService);
importedContentTypes.Add(contentTypeAlias, contentType);
}
//Create and add the child to the list
var content = CreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default);
var content = CreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default, service);
list.Add(content);
//Recursive call
@@ -314,19 +379,26 @@ namespace Umbraco.Core.Packaging
select grand).ToList();
if (grandChildren.Any())
list.AddRange(CreateContentFromXml(grandChildren, content, importedContentTypes));
list.AddRange(CreateContentFromXml(grandChildren, content,importedContentTypes, typeService, service));
}
return list;
}
private IContent CreateContentFromXml(XElement element, IContentType contentType, IContent parent, int parentId)
private T CreateContentFromXml<T, S>(
XElement element,
S contentType,
T parent,
int parentId,
IContentServiceBase<T> service)
where T: class, IContentBase
where S: IContentTypeComposition
{
var key = Guid.Empty;
if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key))
{
//if a Key is supplied, then we need to check if the content already exists and if so we ignore the installation for this item
if (_contentService.GetById(key) != null)
if (service.GetById(key) != null)
return null;
}
@@ -346,9 +418,9 @@ namespace Umbraco.Core.Packaging
var template = templateId.HasValue ? _fileService.GetTemplate(templateId.Value) : null;
//now double check this is correct since its an INT it could very well be pointing to an invalid template :/
if (template != null)
if (template != null && contentType is IContentType contentTypex)
{
if (!contentType.IsAllowedTemplate(template.Alias))
if (!contentTypex.IsAllowedTemplate(template.Alias))
{
//well this is awkward, we'll set the template to null and it will be wired up to the default template
// when it's persisted in the document repository
@@ -356,21 +428,15 @@ namespace Umbraco.Core.Packaging
}
}
IContent content = parent == null
? new Content(nodeName, parentId, contentType)
{
Level = int.Parse(level),
SortOrder = int.Parse(sortOrder),
TemplateId = template?.Id,
Key = key
}
: new Content(nodeName, parent, contentType)
{
Level = int.Parse(level),
SortOrder = int.Parse(sortOrder),
TemplateId = template?.Id,
Key = key
};
T content = CreateContent(
nodeName,
parent,
parentId,
contentType,
key,
int.Parse(level),
int.Parse(sortOrder),
template?.Id);
//Here we make sure that we take composition properties in account as well
//otherwise we would skip them and end up losing content
@@ -396,6 +462,37 @@ namespace Umbraco.Core.Packaging
return content;
}
private T CreateContent<T, S>(string name, T parent, int parentId, S contentType, Guid key, int level, int sortOrder, int? templateId)
where T : class, IContentBase
where S : IContentTypeComposition
{
switch (contentType)
{
case IContentType c:
if (parent is null)
{
return new Content(name, parentId, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T;
}
else
{
return new Content(name, (IContent)parent, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T;
}
case IMediaType m:
if (parent is null)
{
return new Umbraco.Core.Models.Media(name, parentId, m) { Key = key, Level = level, SortOrder = sortOrder, } as T;
}
else
{
return new Umbraco.Core.Models.Media(name, (IMedia)parent, m) { Key = key, Level = level, SortOrder = sortOrder, } as T;
}
default:
throw new NotSupportedException($"Type {typeof(S)} is not supported");
}
}
#endregion
#region DocumentTypes
@@ -413,7 +510,7 @@ namespace Umbraco.Core.Packaging
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId)
{
return ImportDocumentTypes(docTypeElements.ToList(), true, userId);
return ImportDocumentTypes<IContentType>(docTypeElements.ToList(), true, userId, _contentTypeService);
}
/// <summary>
@@ -423,9 +520,10 @@ namespace Umbraco.Core.Packaging
/// <param name="importStructure">Boolean indicating whether or not to import the </param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IContentType> ImportDocumentTypes(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId)
public IReadOnlyList<T> ImportDocumentTypes<T>(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService<T> service)
where T: class, IContentTypeComposition
{
var importedContentTypes = new Dictionary<string, IContentType>();
var importedContentTypes = new Dictionary<string, T>();
//When you are importing a single doc type we have to assume that the dependencies are already there.
//Otherwise something like uSync won't work.
@@ -479,10 +577,10 @@ namespace Umbraco.Core.Packaging
var alias = documentType.Element("Info").Element("Alias").Value;
if (importedContentTypes.ContainsKey(alias) == false)
{
var contentType = _contentTypeService.Get(alias);
var contentType = service.Get(alias);
importedContentTypes.Add(alias, contentType == null
? CreateContentTypeFromXml(documentType, importedContentTypes)
: UpdateContentTypeFromXml(documentType, contentType, importedContentTypes));
? CreateContentTypeFromXml(documentType, importedContentTypes, service)
: UpdateContentTypeFromXml(documentType, contentType, importedContentTypes, service));
}
}
@@ -497,27 +595,27 @@ namespace Umbraco.Core.Packaging
//Save the newly created/updated IContentType objects
var list = importedContentTypes.Select(x => x.Value).ToList();
_contentTypeService.Save(list, userId);
service.Save(list, userId);
//Now we can finish the import by updating the 'structure',
//which requires the doc types to be saved/available in the db
if (importStructure)
{
var updatedContentTypes = new List<IContentType>();
var updatedContentTypes = new List<T>();
//Update the structure here - we can't do it until all DocTypes have been created
foreach (var documentType in documentTypes)
{
var alias = documentType.Element("Info").Element("Alias").Value;
var structureElement = documentType.Element("Structure");
//Ensure that we only update ContentTypes which has actual structure-elements
if (structureElement == null || structureElement.Elements("DocumentType").Any() == false) continue;
if (structureElement == null || structureElement.Elements().Any() == false) continue;
var updated = UpdateContentTypesStructure(importedContentTypes[alias], structureElement, importedContentTypes);
var updated = UpdateContentTypesStructure(importedContentTypes[alias], structureElement, importedContentTypes, service);
updatedContentTypes.Add(updated);
}
//Update ContentTypes with a newly added structure/list of allowed children
if (updatedContentTypes.Any())
_contentTypeService.Save(updatedContentTypes, userId);
service.Save(updatedContentTypes, userId);
}
return list;
@@ -586,33 +684,65 @@ namespace Umbraco.Core.Packaging
return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
}
private IContentType CreateContentTypeFromXml(XElement documentType, IReadOnlyDictionary<string, IContentType> importedContentTypes)
private T CreateContentTypeFromXml<T>(XElement documentType, IReadOnlyDictionary<string, T> importedContentTypes, IContentTypeBaseService<T> service)
where T : class, IContentTypeComposition
{
var infoElement = documentType.Element("Info");
//Name of the master corresponds to the parent
var masterElement = infoElement.Element("Master");
IContentType parent = null;
T parent = default;
if (masterElement != null)
{
var masterAlias = masterElement.Value;
parent = importedContentTypes.ContainsKey(masterAlias)
? importedContentTypes[masterAlias]
: _contentTypeService.Get(masterAlias);
: service.Get(masterAlias);
}
var alias = infoElement.Element("Alias").Value;
var contentType = parent == null
? new ContentType(_shortStringHelper, -1) { Alias = alias }
: new ContentType(_shortStringHelper, parent, alias);
T contentType = CreateContentType(parent, -1, alias);
if (parent != null)
contentType.AddContentType(parent);
return UpdateContentTypeFromXml(documentType, contentType, importedContentTypes);
return UpdateContentTypeFromXml(documentType, contentType, importedContentTypes, service);
}
private IContentType UpdateContentTypeFromXml(XElement documentType, IContentType contentType, IReadOnlyDictionary<string, IContentType> importedContentTypes)
private T CreateContentType<T>(T parent, int parentId, string alias)
where T : class, IContentTypeComposition
{
if (typeof(T) == typeof(IContentType))
{
if (parent is null)
{
return new ContentType(_shortStringHelper, parentId) { Alias = alias } as T;
}
else
{
return new ContentType(_shortStringHelper, (IContentType) parent, alias) as T;
}
}
if (typeof(T) == typeof(IMediaType))
{
if (parent is null)
{
return new MediaType(_shortStringHelper, parentId) { Alias = alias } as T;
}
else
{
return new MediaType(_shortStringHelper, (IMediaType)parent, alias) as T;
}
}
throw new NotSupportedException($"Type {typeof(T)} is not supported");
}
private T UpdateContentTypeFromXml<T>(XElement documentType, T contentType, IReadOnlyDictionary<string, T> importedContentTypes, IContentTypeBaseService<T> service)
where T : IContentTypeComposition
{
var infoElement = documentType.Element("Info");
var defaultTemplateElement = infoElement.Element("DefaultTemplate");
@@ -646,9 +776,9 @@ namespace Umbraco.Core.Packaging
if (masterElement != null)
{
var masterAlias = masterElement.Value;
IContentType parent = importedContentTypes.ContainsKey(masterAlias)
T parent = importedContentTypes.ContainsKey(masterAlias)
? importedContentTypes[masterAlias]
: _contentTypeService.Get(masterAlias);
: service.Get(masterAlias);
contentType.SetParent(parent);
}
@@ -665,13 +795,17 @@ namespace Umbraco.Core.Packaging
var compositionAlias = composition.Value;
var compositionContentType = importedContentTypes.ContainsKey(compositionAlias)
? importedContentTypes[compositionAlias]
: _contentTypeService.Get(compositionAlias);
: service.Get(compositionAlias);
contentType.AddContentType(compositionContentType);
}
}
}
UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement);
if (contentType is IContentType contentTypex)
{
UpdateContentTypesAllowedTemplates(contentTypex, infoElement.Element("AllowedTemplates"), defaultTemplateElement);
}
UpdateContentTypesTabs(contentType, documentType.Element("Tabs"));
UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties"));
@@ -716,7 +850,8 @@ namespace Umbraco.Core.Packaging
}
}
private void UpdateContentTypesTabs(IContentType contentType, XElement tabElement)
private void UpdateContentTypesTabs<T>(T contentType, XElement tabElement)
where T: IContentTypeComposition
{
if (tabElement == null)
return;
@@ -742,7 +877,8 @@ namespace Umbraco.Core.Packaging
}
}
private void UpdateContentTypesProperties(IContentType contentType, XElement genericPropertiesElement)
private void UpdateContentTypesProperties<T>(T contentType, XElement genericPropertiesElement)
where T: IContentTypeComposition
{
var properties = genericPropertiesElement.Elements("GenericProperty");
foreach (var property in properties)
@@ -834,15 +970,16 @@ namespace Umbraco.Core.Packaging
}
}
private IContentType UpdateContentTypesStructure(IContentType contentType, XElement structureElement, IReadOnlyDictionary<string, IContentType> importedContentTypes)
private T UpdateContentTypesStructure<T>(T contentType, XElement structureElement, IReadOnlyDictionary<string, T> importedContentTypes, IContentTypeBaseService<T> service)
where T: IContentTypeComposition
{
var allowedChildren = contentType.AllowedContentTypes.ToList();
int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0;
foreach (var element in structureElement.Elements("DocumentType"))
foreach (var element in structureElement.Elements())
{
var alias = element.Value;
var allowedChild = importedContentTypes.ContainsKey(alias) ? importedContentTypes[alias] : _contentTypeService.Get(alias);
var allowedChild = importedContentTypes.ContainsKey(alias) ? importedContentTypes[alias] : service.Get(alias);
if (allowedChild == null)
{
_logger.LogWarning(
@@ -866,9 +1003,10 @@ namespace Umbraco.Core.Packaging
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <returns></returns>
private IContentType FindContentTypeByAlias(string contentTypeAlias)
private S FindContentTypeByAlias<S>(string contentTypeAlias, IContentTypeBaseService<S> typeService)
where S: IContentTypeComposition
{
var contentType = _contentTypeService.Get(contentTypeAlias);
var contentType = typeService.Get(contentTypeAlias);
if (contentType == null)
throw new Exception($"ContentType matching the passed in Alias: '{contentTypeAlias}' was null");

View File

@@ -1,10 +1,10 @@
using System;
using System;
using Examine;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing.CompositionExtensions;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Grid;
@@ -22,6 +22,7 @@ using Umbraco.Core.Migrations;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Packaging;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.Validators;
@@ -61,15 +62,17 @@ using Umbraco.Web.Templates;
using Umbraco.Web.Trees;
using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter;
namespace Umbraco.Core.Runtime
namespace Umbraco.Infrastructure.Runtime
{
// core's initial composer composes before all core composers
[ComposeBefore(typeof(ICoreComposer))]
public class CoreInitialComposer : ComponentComposer<CoreInitialComponent>
public static class CoreInitialServices
{
public override void Compose(IUmbracoBuilder builder)
public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder)
{
base.Compose(builder);
builder.AddNotificationHandler<UmbracoApplicationStarting, EssentialDirectoryCreator>();
builder.Services.AddSingleton<ManifestWatcher>();
builder.AddNotificationHandler<UmbracoApplicationStarting, ManifestWatcher>(factory => factory.GetRequiredService<ManifestWatcher>());
builder.AddNotificationHandler<UmbracoApplicationStopping, ManifestWatcher>(factory => factory.GetRequiredService<ManifestWatcher>());
// composers
builder
@@ -301,7 +304,7 @@ namespace Umbraco.Core.Runtime
// register *all* checks, except those marked [HideFromTypeFinder] of course
builder.Services.AddUnique<IMarkdownToHtmlConverter, MarkdownToHtmlConverter>();
builder.HealthChecks()
.Add(() => builder.TypeLoader.GetTypes<HealthCheck.HealthCheck>());
.Add(() => builder.TypeLoader.GetTypes<Core.HealthCheck.HealthCheck>());
builder.WithCollectionBuilder<HealthCheckNotificationMethodCollectionBuilder>()
.Add(() => builder.TypeLoader.GetTypes<IHealthCheckNotificationMethod>());
@@ -380,6 +383,11 @@ namespace Umbraco.Core.Runtime
builder.Services.AddUnique<MediaPermissions>();
builder.Services.AddUnique<IImageDimensionExtractor, ImageDimensionExtractor>();
builder.Services.AddUnique<PackageDataInstallation>();
return builder;
}
}
}

View File

@@ -1,7 +1,10 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
@@ -10,71 +13,102 @@ namespace Umbraco.Infrastructure.Runtime
{
public class CoreRuntime : IRuntime
{
public IRuntimeState State { get; }
private readonly ILogger<CoreRuntime> _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly ComponentCollection _components;
private readonly IApplicationShutdownRegistry _applicationShutdownRegistry;
private readonly IProfilingLogger _profilingLogger;
private readonly IMainDom _mainDom;
private readonly IUmbracoDatabaseFactory _databaseFactory;
private readonly IEventAggregator _eventAggregator;
private readonly IHostingEnvironment _hostingEnvironment;
public CoreRuntime(
ILogger<CoreRuntime> logger,
ILoggerFactory loggerFactory,
IRuntimeState state,
ComponentCollection components,
IApplicationShutdownRegistry applicationShutdownRegistry,
IProfilingLogger profilingLogger,
IMainDom mainDom,
IUmbracoDatabaseFactory databaseFactory)
IUmbracoDatabaseFactory databaseFactory,
IEventAggregator eventAggregator,
IHostingEnvironment hostingEnvironment)
{
State = state;
_logger = logger;
_loggerFactory = loggerFactory;
_components = components;
_applicationShutdownRegistry = applicationShutdownRegistry;
_profilingLogger = profilingLogger;
_mainDom = mainDom;
_databaseFactory = databaseFactory;
}
_eventAggregator = eventAggregator;
_hostingEnvironment = hostingEnvironment;
public void Start()
_logger = _loggerFactory.CreateLogger<CoreRuntime>();
}
/// <summary>
/// Gets the state of the Umbraco runtime.
/// </summary>
public IRuntimeState State { get; }
/// <inheritdoc/>
public async Task StartAsync(CancellationToken cancellationToken)
{
StaticApplicationLogging.Initialize(_loggerFactory);
AppDomain.CurrentDomain.UnhandledException += (_, args) =>
{
var exception = (Exception)args.ExceptionObject;
var isTerminating = args.IsTerminating; // always true?
var msg = "Unhandled exception in AppDomain";
if (isTerminating) msg += " (terminating)";
if (isTerminating)
{
msg += " (terminating)";
}
msg += ".";
_logger.LogError(exception, msg);
};
AppDomain.CurrentDomain.SetData("DataDirectory", _hostingEnvironment?.MapPathContentRoot(Core.Constants.SystemDirectories.Data));
DetermineRuntimeLevel();
if (State.Level <= RuntimeLevel.BootFailed)
{
throw new InvalidOperationException($"Cannot start the runtime if the runtime level is less than or equal to {RuntimeLevel.BootFailed}");
}
var hostingEnvironmentLifetime = _applicationShutdownRegistry;
IApplicationShutdownRegistry hostingEnvironmentLifetime = _applicationShutdownRegistry;
if (hostingEnvironmentLifetime == null)
throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(Start)}");
{
throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(StartAsync)}");
}
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
AcquireMainDom();
await _eventAggregator.PublishAsync(new UmbracoApplicationStarting(State.Level), cancellationToken);
// create & initialize the components
_components.Initialize();
}
public void Terminate()
public async Task StopAsync(CancellationToken cancellationToken)
{
_components.Terminate();
await _eventAggregator.PublishAsync(new UmbracoApplicationStopping(), cancellationToken);
StaticApplicationLogging.Initialize(null);
}
private void AcquireMainDom()
{
using (var timer = _profilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
using (DisposableTimer timer = _profilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
{
try
{
@@ -90,7 +124,7 @@ namespace Umbraco.Infrastructure.Runtime
private void DetermineRuntimeLevel()
{
using var timer = _profilingLogger.DebugDuration<CoreRuntime>("Determining runtime level.", "Determined.");
using DisposableTimer timer = _profilingLogger.DebugDuration<CoreRuntime>("Determining runtime level.", "Determined.");
try
{

View File

@@ -1,25 +1,28 @@
using Microsoft.Extensions.Options;
using Umbraco.Core.Composing;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Events;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
namespace Umbraco.Core.Runtime
namespace Umbraco.Infrastructure.Runtime
{
public class CoreInitialComponent : IComponent
public class EssentialDirectoryCreator : INotificationHandler<UmbracoApplicationStarting>
{
private readonly IIOHelper _ioHelper;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly GlobalSettings _globalSettings;
public CoreInitialComponent(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IOptions<GlobalSettings> globalSettings)
public EssentialDirectoryCreator(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IOptions<GlobalSettings> globalSettings)
{
_ioHelper = ioHelper;
_hostingEnvironment = hostingEnvironment;
_globalSettings = globalSettings.Value;
}
public void Initialize()
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
{
// ensure we have some essential directories
// every other component can then initialize safely
@@ -28,9 +31,8 @@ namespace Umbraco.Core.Runtime
_ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MvcViews));
_ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.PartialViews));
_ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MacroPartials));
}
public void Terminate()
{ }
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,65 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Hosting;
using Umbraco.Net;
namespace Umbraco.Infrastructure.Runtime
{
public sealed class ManifestWatcher :
INotificationHandler<UmbracoApplicationStarting>,
INotificationHandler<UmbracoApplicationStopping>
{
private readonly IHostingEnvironment _hosting;
private readonly ILoggerFactory _loggerFactory;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
// if configured and in debug mode, a ManifestWatcher watches App_Plugins folders for
// package.manifest chances and restarts the application on any change
private Core.Manifest.ManifestWatcher _mw;
public ManifestWatcher(IHostingEnvironment hosting, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IUmbracoApplicationLifetime umbracoApplicationLifetime)
{
_hosting = hosting;
_loggerFactory = loggerFactory;
_hostingEnvironment = hostingEnvironment;
_umbracoApplicationLifetime = umbracoApplicationLifetime;
}
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
{
if (_hosting.IsDebugMode == false)
{
return Task.CompletedTask;
}
var appPlugins = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins);
if (Directory.Exists(appPlugins) == false)
{
return Task.CompletedTask;
}
_mw = new Core.Manifest.ManifestWatcher(_loggerFactory.CreateLogger<Core.Manifest.ManifestWatcher>(), _umbracoApplicationLifetime);
_mw.Start(Directory.GetDirectories(appPlugins));
return Task.CompletedTask;
}
public Task HandleAsync(UmbracoApplicationStopping notification, CancellationToken cancellationToken)
{
if (_mw == null)
{
return Task.CompletedTask;
}
_mw.Dispose();
_mw = null;
return Task.CompletedTask;
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Logging;
@@ -387,6 +386,16 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
///
/// </summary>
/// <param name="contents"></param>
/// <param name="userId"></param>
/// <param name="raiseEvents"></param>
/// <returns></returns>
Attempt<OperationResult> IContentServiceBase<IContent>.Save(IEnumerable<IContent> contents, int userId,
bool raiseEvents) => Attempt.Succeed(Save(contents, userId, raiseEvents));
/// <summary>
/// Gets <see cref="IContent"/> objects by Ids
/// </summary>

View File

@@ -4,8 +4,6 @@ using System.Globalization;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Serialization;
@@ -120,6 +118,7 @@ namespace Umbraco.Core.Services.Implement
//xml.Add(new XAttribute("creatorID", media.CreatorId));
xml.Add(new XAttribute("writerName", media.GetWriterProfile(_userService)?.Name ?? string.Empty));
xml.Add(new XAttribute("writerID", media.WriterId));
xml.Add(new XAttribute("udi", media.GetUdi()));
//xml.Add(new XAttribute("template", 0)); // no template for media
@@ -335,6 +334,7 @@ namespace Umbraco.Core.Services.Implement
return xml;
}
public XElement Serialize(IMediaType mediaType)
{
var info = new XElement("Info",
@@ -375,7 +375,7 @@ namespace Umbraco.Core.Services.Implement
new XElement("Validation", propertyType.ValidationRegExp),
new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage),
new XElement("LabelOnTop", propertyType.LabelOnTop),
new XElement("Description", new XCData(propertyType.Description)));
new XElement("Description", new XCData(propertyType.Description ?? string.Empty)));
genericProperties.Add(genericProperty);
}
@@ -498,7 +498,7 @@ namespace Umbraco.Core.Services.Implement
new XElement("Alias", propertyType.Alias),
new XElement("Key", propertyType.Key),
new XElement("Type", propertyType.PropertyEditorAlias),
new XElement("Definition", definition.Key),
new XElement("Definition", definition.Key),
new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name),
new XElement("SortOrder", propertyType.SortOrder),
new XElement("Mandatory", propertyType.Mandatory.ToString()),

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -8,7 +7,6 @@ using Microsoft.Extensions.Logging;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Scoping;
@@ -360,6 +358,8 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets an <see cref="IMedia"/> object by Id
/// </summary>
@@ -643,6 +643,8 @@ namespace Umbraco.Core.Services.Implement
#region Save
/// <summary>
/// Saves a single <see cref="IMedia"/> object
/// </summary>

View File

@@ -33,54 +33,6 @@ namespace Umbraco.Tests.Integration
MyComposer.Reset();
}
/// <summary>
/// Calling AddUmbracoCore to configure the container
/// </summary>
[Test]
public async Task AddUmbracoCore()
{
var testHelper = new TestHelper();
var hostBuilder = new HostBuilder()
.UseUmbraco()
.ConfigureServices((hostContext, services) =>
{
var webHostEnvironment = testHelper.GetWebHostEnvironment();
services.AddSingleton(testHelper.DbProviderFactoryCreator);
services.AddRequiredNetCoreServices(testHelper, webHostEnvironment);
// Add it!
var typeLoader = services.AddTypeLoader(
GetType().Assembly,
webHostEnvironment,
testHelper.GetHostingEnvironment(),
testHelper.ConsoleLoggerFactory,
AppCaches.NoCache,
hostContext.Configuration,
testHelper.Profiler);
var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory);
builder.Services.AddUnique<AppCaches>(AppCaches.NoCache);
builder.AddConfiguration();
builder.AddUmbracoCore();
});
var host = await hostBuilder.StartAsync();
var app = new ApplicationBuilder(host.Services);
// assert results
var runtimeState = app.ApplicationServices.GetRequiredService<IRuntimeState>();
var mainDom = app.ApplicationServices.GetRequiredService<IMainDom>();
Assert.IsFalse(mainDom.IsMainDom); // We haven't "Started" the runtime yet
Assert.IsNull(runtimeState.BootFailedException);
Assert.IsFalse(MyComponent.IsInit); // We haven't "Started" the runtime yet
await host.StopAsync();
Assert.IsFalse(MyComponent.IsTerminated); // we didn't "Start" the runtime so nothing was registered for shutdown
}
/// <summary>
/// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime
/// </summary>
@@ -91,7 +43,6 @@ namespace Umbraco.Tests.Integration
var testHelper = new TestHelper();
var hostBuilder = new HostBuilder()
.UseUmbraco()
.ConfigureServices((hostContext, services) =>
{
var webHostEnvironment = testHelper.GetWebHostEnvironment();
@@ -109,11 +60,12 @@ namespace Umbraco.Tests.Integration
hostContext.Configuration,
testHelper.Profiler);
var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory);
var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader,
testHelper.ConsoleLoggerFactory);
builder.Services.AddUnique<AppCaches>(AppCaches.NoCache);
builder.AddConfiguration()
.AddUmbracoCore()
.Build();
.AddUmbracoCore()
.Build();
services.AddRouting(); // LinkGenerator
});

View File

@@ -1,4 +1,3 @@
using System;
using System.Linq.Expressions;
using System.Net.Http;
@@ -36,7 +35,7 @@ namespace Umbraco.Tests.Integration.TestServerTest
InMemoryConfiguration["Umbraco:CMS:Hosting:Debug"] = "true";
// create new WebApplicationFactory specifying 'this' as the IStartup instance
var factory = new UmbracoWebApplicationFactory<UmbracoTestServerTestBase>(CreateHostBuilder);
var factory = new UmbracoWebApplicationFactory<UmbracoTestServerTestBase>(CreateHostBuilder, BeforeHostStart);
// additional host configuration for web server integration tests
Factory = factory.WithWebHostBuilder(builder =>
@@ -72,11 +71,10 @@ namespace Umbraco.Tests.Integration.TestServerTest
// call startup
builder.Configure(app =>
{
UseTestLocalDb(app.ApplicationServices);
Services = app.ApplicationServices;
Configure(app);
});
}).UseEnvironment(Environments.Development);
}).UseEnvironment(Environments.Development);
return builder;
}
@@ -118,15 +116,6 @@ namespace Umbraco.Tests.Integration.TestServerTest
protected WebApplicationFactory<UmbracoTestServerTestBase> Factory { get; private set; }
[TearDown]
public override void TearDown()
{
base.TearDown();
TerminateCoreRuntime();
Factory.Dispose();
}
public override void ConfigureServices(IServiceCollection services)
{
services.AddTransient<TestUmbracoDatabaseFactoryProvider>();

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Hosting;
@@ -8,16 +8,30 @@ namespace Umbraco.Tests.Integration.TestServerTest
public class UmbracoWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
private readonly Func<IHostBuilder> _createHostBuilder;
private readonly Action<IHost> _beforeStart;
/// <summary>
/// Constructor to create a new WebApplicationFactory
/// </summary>
/// <param name="createHostBuilder">Method to create the IHostBuilder</param>
public UmbracoWebApplicationFactory(Func<IHostBuilder> createHostBuilder)
/// <param name="beforeStart">Method to perform an action before IHost starts</param>
public UmbracoWebApplicationFactory(Func<IHostBuilder> createHostBuilder, Action<IHost> beforeStart = null)
{
_createHostBuilder = createHostBuilder;
_beforeStart = beforeStart;
}
protected override IHostBuilder CreateHostBuilder() => _createHostBuilder();
protected override IHost CreateHost(IHostBuilder builder)
{
IHost host = builder.Build();
_beforeStart?.Invoke(host);
host.Start();
return host;
}
}
}

View File

@@ -17,9 +17,11 @@ namespace Umbraco.Tests.Integration.Testing
{
protected ILoggerFactory _loggerFactory;
protected IUmbracoDatabaseFactory _databaseFactory;
protected IEnumerable<TestDbMeta> _testDatabases;
protected UmbracoDatabase.CommandInfo[] _cachedDatabaseInitCommands;
protected IList<TestDbMeta> _testDatabases;
protected const int _threadCount = 2;
protected UmbracoDatabase.CommandInfo[] _cachedDatabaseInitCommands = new UmbracoDatabase.CommandInfo[0];
protected BlockingCollection<TestDbMeta> _prepareQueue;
protected BlockingCollection<TestDbMeta> _readySchemaQueue;
@@ -92,46 +94,52 @@ namespace Umbraco.Tests.Integration.Testing
});
}
protected void RebuildSchema(IDbCommand command, TestDbMeta meta)
private void RebuildSchema(IDbCommand command, TestDbMeta meta)
{
if (_cachedDatabaseInitCommands != null)
lock (_cachedDatabaseInitCommands)
{
foreach (var dbCommand in _cachedDatabaseInitCommands)
if (!_cachedDatabaseInitCommands.Any())
{
if (dbCommand.Text.StartsWith("SELECT "))
{
continue;
}
command.CommandText = dbCommand.Text;
command.Parameters.Clear();
foreach (var parameterInfo in dbCommand.Parameters)
{
AddParameter(command, parameterInfo);
}
command.ExecuteNonQuery();
RebuildSchemaFirstTime(command, meta);
return;
}
}
else
foreach (var dbCommand in _cachedDatabaseInitCommands)
{
_databaseFactory.Configure(meta.ConnectionString, Core.Constants.DatabaseProviders.SqlServer);
using (var database = (UmbracoDatabase)_databaseFactory.CreateDatabase())
if (dbCommand.Text.StartsWith("SELECT "))
{
database.LogCommands = true;
continue;
}
using (var transaction = database.GetTransaction())
{
var schemaCreator = new DatabaseSchemaCreator(database, _loggerFactory.CreateLogger<DatabaseSchemaCreator>(), _loggerFactory, new UmbracoVersion());
schemaCreator.InitializeDatabaseSchema();
command.CommandText = dbCommand.Text;
command.Parameters.Clear();
transaction.Complete();
foreach (var parameterInfo in dbCommand.Parameters)
{
AddParameter(command, parameterInfo);
}
_cachedDatabaseInitCommands = database.Commands.ToArray();
}
command.ExecuteNonQuery();
}
}
private void RebuildSchemaFirstTime(IDbCommand command, TestDbMeta meta)
{
_databaseFactory.Configure(meta.ConnectionString, Core.Constants.DatabaseProviders.SqlServer);
using (var database = (UmbracoDatabase)_databaseFactory.CreateDatabase())
{
database.LogCommands = true;
using (var transaction = database.GetTransaction())
{
var schemaCreator = new DatabaseSchemaCreator(database, _loggerFactory.CreateLogger<DatabaseSchemaCreator>(), _loggerFactory, new UmbracoVersion());
schemaCreator.InitializeDatabaseSchema();
transaction.Complete();
_cachedDatabaseInitCommands = database.Commands.ToArray();
}
}
}

View File

@@ -19,8 +19,6 @@ namespace Umbraco.Tests.Integration.Testing
private static LocalDb.Instance _localDbInstance;
private static string _filesPath;
private const int _threadCount = 2;
public static LocalDbTestDatabase Instance { get; private set; }
//It's internal because `Umbraco.Core.Persistence.LocalDb` is internal
@@ -64,13 +62,17 @@ namespace Umbraco.Tests.Integration.Testing
var tempName = Guid.NewGuid().ToString("N");
_localDbInstance.CreateDatabase(tempName, _filesPath);
_localDbInstance.DetachDatabase(tempName);
_prepareQueue = new BlockingCollection<TestDbMeta>();
_readySchemaQueue = new BlockingCollection<TestDbMeta>();
_readyEmptyQueue = new BlockingCollection<TestDbMeta>();
foreach (var meta in _testDatabases)
for (var i = 0; i < _testDatabases.Count; i++)
{
_localDb.CopyDatabaseFiles(tempName, _filesPath, targetDatabaseName: meta.Name, overwrite: true, delete: false);
var meta = _testDatabases[i];
var isLast = i == _testDatabases.Count - 1;
_localDb.CopyDatabaseFiles(tempName, _filesPath, targetDatabaseName: meta.Name, overwrite: true, delete: isLast);
meta.ConnectionString = _localDbInstance.GetAttachedConnectionString(meta.Name, _filesPath);
_prepareQueue.Add(meta);
}
@@ -85,7 +87,9 @@ namespace Umbraco.Tests.Integration.Testing
public void Finish()
{
if (_prepareQueue == null)
{
return;
}
_prepareQueue.CompleteAdding();
while (_prepareQueue.TryTake(out _))
@@ -100,14 +104,18 @@ namespace Umbraco.Tests.Integration.Testing
{ }
if (_filesPath == null)
{
return;
}
var filename = Path.Combine(_filesPath, DatabaseName).ToUpper();
foreach (var database in _localDbInstance.GetDatabases())
{
if (database.StartsWith(filename))
{
_localDbInstance.DropDatabase(database);
}
}
foreach (var file in Directory.EnumerateFiles(_filesPath))

View File

@@ -17,8 +17,6 @@ namespace Umbraco.Tests.Integration.Testing
private readonly string _masterConnectionString;
public const string DatabaseName = "UmbracoTests";
private const int _threadCount = 2;
public static SqlDeveloperTestDatabase Instance { get; private set; }
public SqlDeveloperTestDatabase(ILoggerFactory loggerFactory, IUmbracoDatabaseFactory databaseFactory, string masterConnectionString)

View File

@@ -1,4 +1,5 @@
using System;
using System.IO;
using Microsoft.Extensions.Logging;
using Umbraco.Core.Persistence;
@@ -8,13 +9,20 @@ namespace Umbraco.Tests.Integration.Testing
{
public static ITestDatabase Create(string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory)
{
return string.IsNullOrEmpty(Environment.GetEnvironmentVariable("UmbracoIntegrationTestConnectionString"))
? CreateLocalDb(filesPath, loggerFactory, dbFactory.Create())
: CreateSqlDeveloper(loggerFactory, dbFactory.Create());
var connectionString = Environment.GetEnvironmentVariable("UmbracoIntegrationTestConnectionString");
return string.IsNullOrEmpty(connectionString)
? CreateLocalDb(filesPath, loggerFactory, dbFactory)
: CreateSqlDeveloper(loggerFactory, dbFactory, connectionString);
}
private static ITestDatabase CreateLocalDb(string filesPath, ILoggerFactory loggerFactory, IUmbracoDatabaseFactory dbFactory)
private static ITestDatabase CreateLocalDb(string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory)
{
if (!Directory.Exists(filesPath))
{
Directory.CreateDirectory(filesPath);
}
var localDb = new LocalDb();
if (!localDb.IsAvailable)
@@ -22,22 +30,21 @@ namespace Umbraco.Tests.Integration.Testing
throw new InvalidOperationException("LocalDB is not available.");
}
return new LocalDbTestDatabase(loggerFactory, localDb, filesPath, dbFactory);
return new LocalDbTestDatabase(loggerFactory, localDb, filesPath, dbFactory.Create());
}
private static ITestDatabase CreateSqlDeveloper(ILoggerFactory loggerFactory, IUmbracoDatabaseFactory dbFactory)
private static ITestDatabase CreateSqlDeveloper(ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory, string connectionString)
{
// NOTE: Example setup for Linux box.
// $ export SA_PASSWORD=Foobar123!
// $ export UmbracoIntegrationTestConnectionString="Server=localhost,1433;User Id=sa;Password=$SA_PASSWORD;"
// $ docker run -e 'ACCEPT_EULA=Y' -e "SA_PASSWORD=$SA_PASSWORD" -e 'MSSQL_PID=Developer' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu
var connectionString = Environment.GetEnvironmentVariable("UmbracoIntegrationTestConnectionString");
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException("ENV: UmbracoIntegrationTestConnectionString is not set");
}
return new SqlDeveloperTestDatabase(loggerFactory, dbFactory, connectionString);
return new SqlDeveloperTestDatabase(loggerFactory, dbFactory.Create(), connectionString);
}
}
}

View File

@@ -71,9 +71,14 @@ namespace Umbraco.Tests.Integration.Testing
foreach (var a in _testTeardown)
a();
}
_testTeardown = null;
FirstTestInFixture = false;
FirstTestInSession = false;
// Ensure CoreRuntime stopped (now it's a HostedService)
IHost host = Services.GetRequiredService<IHost>();
host.StopAsync().GetAwaiter().GetResult();
}
[TearDown]
@@ -94,14 +99,18 @@ namespace Umbraco.Tests.Integration.Testing
InMemoryConfiguration[Constants.Configuration.ConfigGlobal + ":" + nameof(GlobalSettings.InstallEmptyDatabase)] = "true";
var hostBuilder = CreateHostBuilder();
var host = hostBuilder.Start();
IHost host = hostBuilder.Build();
BeforeHostStart(host);
host.Start();
Services = host.Services;
var app = new ApplicationBuilder(host.Services);
Configure(app);
}
OnFixtureTearDown(() => host.Dispose());
protected void BeforeHostStart(IHost host)
{
Services = host.Services;
UseTestDatabase(Services);
}
#region Generic Host Builder and Runtime
@@ -110,13 +119,21 @@ namespace Umbraco.Tests.Integration.Testing
{
try
{
var testOptions = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
switch (testOptions.Logger)
switch (TestOptions.Logger)
{
case UmbracoTestOptions.Logger.Mock:
return NullLoggerFactory.Instance;
case UmbracoTestOptions.Logger.Serilog:
return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); });
return Microsoft.Extensions.Logging.LoggerFactory.Create(builder =>
{
var path = Path.Combine(TestHelper.WorkingDirectory, "logs", "umbraco_integration_tests_.txt");
Log.Logger = new LoggerConfiguration()
.WriteTo.File(path, rollingInterval: RollingInterval.Day)
.CreateLogger();
builder.AddSerilog(Log.Logger);
});
case UmbracoTestOptions.Logger.Console:
return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); });
}
@@ -141,7 +158,6 @@ namespace Umbraco.Tests.Integration.Testing
// create separate Host instances. So instead of UseStartup, we just call ConfigureServices/Configure ourselves,
// and in the case of the UmbracoTestServerTestBase it will use the ConfigureWebHost to Configure the IApplicationBuilder directly.
//.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(GetType()); })
.UseUmbraco()
.ConfigureAppConfiguration((context, configBuilder) =>
{
context.HostingEnvironment = TestHelper.GetWebHostEnvironment();
@@ -152,8 +168,15 @@ namespace Umbraco.Tests.Integration.Testing
})
.ConfigureServices((hostContext, services) =>
{
services.AddTransient(_ => CreateLoggerFactory());
ConfigureServices(services);
services.AddUnique(CreateLoggerFactory());
if (!TestOptions.Boot)
{
// If boot is false, we don't want the CoreRuntime hosted service to start
// So we replace it with a Mock
services.AddUnique(Mock.Of<IRuntime>());
}
});
return hostBuilder;
}
@@ -213,29 +236,13 @@ namespace Umbraco.Tests.Integration.Testing
public virtual void Configure(IApplicationBuilder app)
{
UseTestLocalDb(app.ApplicationServices);
//get the currently set options
var testOptions = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
if (testOptions.Boot)
if (TestOptions.Boot)
{
Services.GetRequiredService<IBackOfficeSecurityFactory>().EnsureBackOfficeSecurity();
Services.GetRequiredService<IUmbracoContextFactory>().EnsureUmbracoContext();
app.UseUmbracoCore(); // Takes 200 ms
OnTestTearDown(TerminateCoreRuntime);
}
}
/// <remarks>
/// Some IComponents hook onto static events (e.g. Published in ContentService)
/// If these fire after the components host has been shutdown, errors can occur.
/// If CoreRuntime.Start() is called We also need to de-register the events.
/// </remarks>
protected void TerminateCoreRuntime()
{
Services.GetRequiredService<IRuntime>().Terminate();
StaticApplicationLogging.Initialize(null);
app.UseUmbracoCore(); // This no longer starts CoreRuntime, it's very fast
}
#endregion
@@ -246,25 +253,20 @@ namespace Umbraco.Tests.Integration.Testing
private static ITestDatabase _dbInstance;
private static TestDbMeta _fixtureDbMeta;
protected void UseTestLocalDb(IServiceProvider serviceProvider)
protected void UseTestDatabase(IServiceProvider serviceProvider)
{
var state = serviceProvider.GetRequiredService<IRuntimeState>();
var testDatabaseFactoryProvider = serviceProvider.GetRequiredService<TestUmbracoDatabaseFactoryProvider>();
var databaseFactory = serviceProvider.GetRequiredService<IUmbracoDatabaseFactory>();
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
// This will create a db, install the schema and ensure the app is configured to run
InstallTestLocalDb(testDatabaseFactoryProvider, databaseFactory, serviceProvider.GetRequiredService<ILoggerFactory>(), state, TestHelper.WorkingDirectory);
SetupTestDatabase(testDatabaseFactoryProvider, databaseFactory, loggerFactory, state, TestHelper.WorkingDirectory);
}
/// <summary>
/// Get or create an instance of <see cref="LocalDbTestDatabase"/>
/// Get or create an instance of <see cref="ITestDatabase"/>
/// </summary>
/// <param name="filesPath"></param>
/// <param name="logger"></param>
/// <param name="loggerFactory"></param>
/// <param name="globalSettings"></param>
/// <param name="dbFactory"></param>
/// <returns></returns>
/// <remarks>
/// There must only be ONE instance shared between all tests in a session
/// </remarks>
@@ -273,9 +275,12 @@ namespace Umbraco.Tests.Integration.Testing
lock (_dbLocker)
{
if (_dbInstance != null)
{
return _dbInstance;
}
_dbInstance = TestDatabaseFactory.Create(filesPath, loggerFactory, dbFactory);
return _dbInstance;
}
}
@@ -283,65 +288,47 @@ namespace Umbraco.Tests.Integration.Testing
/// <summary>
/// Creates a LocalDb instance to use for the test
/// </summary>
private void InstallTestLocalDb(
private void SetupTestDatabase(
TestUmbracoDatabaseFactoryProvider testUmbracoDatabaseFactoryProvider,
IUmbracoDatabaseFactory databaseFactory,
ILoggerFactory loggerFactory,
IRuntimeState runtimeState,
string workingDirectory)
{
var dbFilePath = Path.Combine(workingDirectory, "LocalDb");
// get the currently set db options
var testOptions = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
if (testOptions.Database == UmbracoTestOptions.Database.None)
if (TestOptions.Database == UmbracoTestOptions.Database.None)
{
return;
}
// need to manually register this factory
DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);
if (!Directory.Exists(dbFilePath))
Directory.CreateDirectory(dbFilePath);
var dbFilePath = Path.Combine(workingDirectory, "LocalDb");
var db = GetOrCreateDatabase(dbFilePath, loggerFactory, testUmbracoDatabaseFactoryProvider);
switch (testOptions.Database)
switch (TestOptions.Database)
{
case UmbracoTestOptions.Database.NewSchemaPerTest:
// New DB + Schema
var newSchemaDbMeta = db.AttachSchema();
TestDbMeta newSchemaDbMeta = db.AttachSchema();
// Add teardown callback
OnTestTearDown(() => db.Detach(newSchemaDbMeta));
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
if (!databaseFactory.Configured)
{
databaseFactory.Configure(newSchemaDbMeta.ConnectionString, Constants.DatabaseProviders.SqlServer);
}
// re-run the runtime level check
runtimeState.DetermineRuntimeLevel();
ConfigureTestDatabaseFactory(newSchemaDbMeta, databaseFactory, runtimeState);
Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
break;
case UmbracoTestOptions.Database.NewEmptyPerTest:
var newEmptyDbMeta = db.AttachEmpty();
TestDbMeta newEmptyDbMeta = db.AttachEmpty();
// Add teardown callback
OnTestTearDown(() => db.Detach(newEmptyDbMeta));
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
if (!databaseFactory.Configured)
{
databaseFactory.Configure(newEmptyDbMeta.ConnectionString, Constants.DatabaseProviders.SqlServer);
}
// re-run the runtime level check
runtimeState.DetermineRuntimeLevel();
ConfigureTestDatabaseFactory(newEmptyDbMeta, databaseFactory, runtimeState);
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
@@ -353,21 +340,14 @@ namespace Umbraco.Tests.Integration.Testing
if (FirstTestInFixture)
{
// New DB + Schema
var newSchemaFixtureDbMeta = db.AttachSchema();
TestDbMeta newSchemaFixtureDbMeta = db.AttachSchema();
_fixtureDbMeta = newSchemaFixtureDbMeta;
// Add teardown callback
OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbMeta));
}
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
if (!databaseFactory.Configured)
{
databaseFactory.Configure(_fixtureDbMeta.ConnectionString, Constants.DatabaseProviders.SqlServer);
}
// re-run the runtime level check
runtimeState.DetermineRuntimeLevel();
ConfigureTestDatabaseFactory(_fixtureDbMeta, databaseFactory, runtimeState);
break;
case UmbracoTestOptions.Database.NewEmptyPerFixture:
@@ -377,29 +357,40 @@ namespace Umbraco.Tests.Integration.Testing
if (FirstTestInFixture)
{
// New DB + Schema
var newEmptyFixtureDbMeta = db.AttachEmpty();
TestDbMeta newEmptyFixtureDbMeta = db.AttachEmpty();
_fixtureDbMeta = newEmptyFixtureDbMeta;
// Add teardown callback
OnFixtureTearDown(() => db.Detach(newEmptyFixtureDbMeta));
}
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
if (!databaseFactory.Configured)
{
databaseFactory.Configure(_fixtureDbMeta.ConnectionString, Constants.DatabaseProviders.SqlServer);
}
ConfigureTestDatabaseFactory(_fixtureDbMeta, databaseFactory, runtimeState);
break;
default:
throw new ArgumentOutOfRangeException(nameof(testOptions), testOptions, null);
throw new ArgumentOutOfRangeException(nameof(TestOptions), TestOptions, null);
}
}
private void ConfigureTestDatabaseFactory(TestDbMeta meta, IUmbracoDatabaseFactory factory, IRuntimeState state)
{
ILogger<UmbracoIntegrationTest> log = Services.GetRequiredService<ILogger<UmbracoIntegrationTest>>();
log.LogInformation($"ConfigureTestDatabaseFactory - Using test database: [{meta.Name}] - IsEmpty: [{meta.IsEmpty}]");
// It's just been pulled from container and wasn't used to create test database
Assert.IsFalse(factory.Configured);
factory.Configure(meta.ConnectionString, Constants.DatabaseProviders.SqlServer);
state.DetermineRuntimeLevel();
log.LogInformation($"ConfigureTestDatabaseFactory - Determined RuntimeLevel: [{state.Level}]");
}
#endregion
#region Common services
protected UmbracoTestAttribute TestOptions => TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
protected virtual T GetRequiredService<T>() => Services.GetRequiredService<T>();
public Dictionary<string, string> InMemoryConfiguration { get; } = new Dictionary<string, string>();
@@ -429,7 +420,6 @@ namespace Umbraco.Tests.Integration.Testing
/// Returns the <see cref="ILoggerFactory"/>
/// </summary>
protected ILoggerFactory LoggerFactory => Services.GetRequiredService<ILoggerFactory>();
protected AppCaches AppCaches => Services.GetRequiredService<AppCaches>();
protected IIOHelper IOHelper => Services.GetRequiredService<IIOHelper>();
protected IShortStringHelper ShortStringHelper => Services.GetRequiredService<IShortStringHelper>();

View File

@@ -45,6 +45,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging
private IEntityXmlSerializer EntityXmlSerializer => GetRequiredService<IEntityXmlSerializer>();
private IHostingEnvironment HostingEnvironment => GetRequiredService<IHostingEnvironment>();
private IUmbracoVersion UmbracoVersion => GetRequiredService<IUmbracoVersion>();
private IMediaService MediaService => GetRequiredService<IMediaService>();
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
public ICreatedPackagesRepository PackageBuilder => new PackagesRepository(
ContentService, ContentTypeService, DataTypeService,
@@ -53,6 +55,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging
EntityXmlSerializer, LoggerFactory,
UmbracoVersion,
Microsoft.Extensions.Options.Options.Create(new GlobalSettings()),
MediaService,
MediaTypeService,
"createdPackages.config",
//temp paths
tempFolderPath: "~/" + _testBaseFolder + "/temp",
@@ -158,8 +162,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging
{
var file1 = $"~/{_testBaseFolder}/App_Plugins/MyPlugin/package.manifest";
var file2 = $"~/{_testBaseFolder}/App_Plugins/MyPlugin/styles.css";
var mappedFile1 = IOHelper.MapPath(file1);
var mappedFile2 = IOHelper.MapPath(file2);
var mappedFile1 = HostingEnvironment.MapPathContentRoot(file1);
var mappedFile2 = HostingEnvironment.MapPathContentRoot(file2);
Directory.CreateDirectory(Path.GetDirectoryName(mappedFile1));
Directory.CreateDirectory(Path.GetDirectoryName(mappedFile2));
File.WriteAllText(mappedFile1, "hello world");
@@ -183,7 +187,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging
def = PackageBuilder.GetById(def.Id); //re-get
Assert.IsNotNull(def.PackagePath);
using (var archive = ZipFile.OpenRead(IOHelper.MapPath(zip)))
using (var archive = ZipFile.OpenRead(HostingEnvironment.MapPathWebRoot(zip)))
{
Assert.AreEqual(3, archive.Entries.Count);

View File

@@ -2,13 +2,11 @@
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing.CompositionExtensions;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Packaging;
@@ -18,7 +16,7 @@ using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Tests.Services;
using Umbraco.Tests.Integration.Testing;
using Umbraco.Tests.Services.Importing;
using Umbraco.Tests.Testing;
@@ -27,9 +25,12 @@ namespace Umbraco.Tests.Packaging
[TestFixture]
[Category("Slow")]
[Apartment(ApartmentState.STA)]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class PackageDataInstallationTests : TestWithSomeContentBase
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)]
public class PackageDataInstallationTests : UmbracoIntegrationTestWithContent
{
private ILocalizationService LocalizationService => GetRequiredService<ILocalizationService>();
private IMacroService MacroService => GetRequiredService<IMacroService>();
[HideFromTypeFinder]
[DataEditor("7e062c13-7c41-4ad9-b389-41d88aeef87c", "Editor1", "editor1")]
public class Editor1 : DataEditor
@@ -50,31 +51,36 @@ namespace Umbraco.Tests.Packaging
}
}
protected override void Compose()
{
base.Compose();
// protected override void Compose()
// {
// base.Compose();
//
// // the packages that are used by these tests reference totally bogus property
// // editors that must exist - so they are defined here - and in order not to
// // pollute everything, they are ignored by the type finder and explicitely
// // added to the editors collection
//
// Builder.WithCollectionBuilder<DataEditorCollectionBuilder>()
// .Add<Editor1>()
// .Add<Editor2>();
// }
//
// protected override void ComposeApplication(bool withApplication)
// {
// base.ComposeApplication(withApplication);
//
// if (!withApplication) return;
//
// // re-register with actual media fs
// Builder.ComposeFileSystems();
// }
// the packages that are used by these tests reference totally bogus property
// editors that must exist - so they are defined here - and in order not to
// pollute everything, they are ignored by the type finder and explicitely
// added to the editors collection
private PackageDataInstallation PackageDataInstallation => GetRequiredService<PackageDataInstallation>();
private IContentService ContentService => GetRequiredService<IContentService>();
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
Builder.WithCollectionBuilder<DataEditorCollectionBuilder>()
.Add<Editor1>()
.Add<Editor2>();
}
protected override void ComposeApplication(bool withApplication)
{
base.ComposeApplication(withApplication);
if (!withApplication) return;
// re-register with actual media fs
Builder.ComposeFileSystems();
}
private PackageDataInstallation PackageDataInstallation => Factory.GetRequiredService<PackageDataInstallation>();
private IMediaService MediaService => GetRequiredService<IMediaService>();
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
[Test]
public void Can_Import_uBlogsy_ContentTypes_And_Verify_Structure()
@@ -195,12 +201,12 @@ namespace Umbraco.Tests.Packaging
var xml = XElement.Parse(strXml);
var element = xml.Descendants("Templates").First();
var init = ServiceContext.FileService.GetTemplates().Count();
var init = FileService.GetTemplates().Count();
// Act
var templates = PackageDataInstallation.ImportTemplates(element.Elements("Template").ToList(), 0);
var numberOfTemplates = (from doc in element.Elements("Template") select doc).Count();
var allTemplates = ServiceContext.FileService.GetTemplates();
var allTemplates = FileService.GetTemplates();
// Assert
Assert.That(templates, Is.Not.Null);
@@ -322,16 +328,16 @@ namespace Umbraco.Tests.Packaging
var dataTypeElement = xml.Descendants("DataTypes").First();
var docTypesElement = xml.Descendants("DocumentTypes").First();
var element = xml.Descendants("DocumentSet").First();
var packageDocument = CompiledPackageDocument.Create(element);
var packageDocument = CompiledPackageContentBase.Create(element);
// Act
var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0);
var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0);
var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x);
var contents = PackageDataInstallation.ImportContent(packageDocument, -1, importedContentTypes, 0);
var contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService);
var numberOfDocs = (from doc in element.Descendants()
where (string) doc.Attribute("isDoc") == ""
select doc).Count();
where (string) doc.Attribute("isDoc") == ""
select doc).Count();
// Assert
Assert.That(contents, Is.Not.Null);
@@ -341,6 +347,32 @@ namespace Umbraco.Tests.Packaging
Assert.That(contents.Count(), Is.EqualTo(numberOfDocs));
}
[Test]
public void Can_Import_Media_Package_Xml()
{
// Arrange
Core.Services.Implement.MediaTypeService.ClearScopeEvents();
string strXml = ImportResources.MediaTypesAndMedia_Package_xml;
var xml = XElement.Parse(strXml);
var mediaTypesElement = xml.Descendants("MediaTypes").First();
var element = xml.Descendants("MediaSet").First();
var packageMedia = CompiledPackageContentBase.Create(element);
// Act
var mediaTypes = PackageDataInstallation.ImportMediaTypes(mediaTypesElement.Elements("MediaType"), 0);
var importedMediaTypes = mediaTypes.ToDictionary(x => x.Alias, x => x);
var medias = PackageDataInstallation.ImportContentBase(packageMedia.Yield(), importedMediaTypes, 0, MediaTypeService, MediaService);
var numberOfDocs = (from doc in element.Descendants()
where (string) doc.Attribute("isDoc") == ""
select doc).Count();
// Assert
Assert.That(medias, Is.Not.Null);
Assert.That(mediaTypes.Any(), Is.True);
Assert.That(medias.Any(), Is.True);
Assert.That(medias.Count(), Is.EqualTo(numberOfDocs));
}
[Test]
public void Can_Import_CheckboxList_Content_Package_Xml_With_Property_Editor_Aliases()
{
@@ -356,13 +388,13 @@ namespace Umbraco.Tests.Packaging
var dataTypeElement = xml.Descendants("DataTypes").First();
var docTypesElement = xml.Descendants("DocumentTypes").First();
var element = xml.Descendants("DocumentSet").First();
var packageDocument = CompiledPackageDocument.Create(element);
var packageDocument = CompiledPackageContentBase.Create(element);
// Act
var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0);
var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0);
var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x);
var contents = PackageDataInstallation.ImportContent(packageDocument, -1, importedContentTypes, 0);
var contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService);
var numberOfDocs = (from doc in element.Descendants()
where (string)doc.Attribute("isDoc") == ""
select doc).Count();
@@ -427,7 +459,7 @@ namespace Umbraco.Tests.Packaging
string strXml = ImportResources.SingleDocType;
var docTypeElement = XElement.Parse(strXml);
var serializer = Factory.GetRequiredService<IEntityXmlSerializer>();
var serializer = GetRequiredService<IEntityXmlSerializer>();
// Act
var contentTypes = PackageDataInstallation.ImportDocumentType(docTypeElement, 0);
@@ -476,7 +508,7 @@ namespace Umbraco.Tests.Packaging
var templateElement = newPackageXml.Descendants("Templates").First();
var templateElementUpdated = updatedPackageXml.Descendants("Templates").First();
var fileService = ServiceContext.FileService;
var fileService = FileService;
// kill default test data
fileService.DeleteTemplate("Textpage");
@@ -535,11 +567,11 @@ namespace Umbraco.Tests.Packaging
var dictionaryItems = PackageDataInstallation.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0);
// Assert
Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(parentKey), "DictionaryItem parentKey does not exist");
Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(childKey), "DictionaryItem childKey does not exist");
Assert.That(LocalizationService.DictionaryItemExists(parentKey), "DictionaryItem parentKey does not exist");
Assert.That(LocalizationService.DictionaryItemExists(childKey), "DictionaryItem childKey does not exist");
var parentDictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey(parentKey);
var childDictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey(childKey);
var parentDictionaryItem = LocalizationService.GetDictionaryItemByKey(parentKey);
var childDictionaryItem = LocalizationService.GetDictionaryItemByKey(childKey);
Assert.That(parentDictionaryItem.ParentId, Is.Not.EqualTo(childDictionaryItem.ParentId));
Assert.That(childDictionaryItem.ParentId, Is.EqualTo(parentDictionaryItem.Key));
@@ -604,7 +636,7 @@ namespace Umbraco.Tests.Packaging
// Act
var languages = PackageDataInstallation.ImportLanguages(LanguageItemsElement.Elements("Language"), 0);
var allLanguages = ServiceContext.LocalizationService.GetAllLanguages();
var allLanguages = LocalizationService.GetAllLanguages();
// Assert
Assert.That(languages.Any(x => x.HasIdentity == false), Is.False);
@@ -629,7 +661,7 @@ namespace Umbraco.Tests.Packaging
// Assert
Assert.That(macros.Any(), Is.True);
var allMacros = ServiceContext.MacroService.GetAll().ToList();
var allMacros = MacroService.GetAll().ToList();
foreach (var macro in macros)
{
Assert.That(allMacros.Any(x => x.Alias == macro.Alias), Is.True);
@@ -652,7 +684,7 @@ namespace Umbraco.Tests.Packaging
Assert.That(macros.Any(), Is.True);
Assert.That(macros.First().Properties.Values.Any(), Is.True);
var allMacros = ServiceContext.MacroService.GetAll().ToList();
var allMacros = MacroService.GetAll().ToList();
foreach (var macro in macros)
{
Assert.That(allMacros.Any(x => x.Alias == macro.Alias), Is.True);
@@ -718,14 +750,14 @@ namespace Umbraco.Tests.Packaging
var globalSettings = new GlobalSettings();
var norwegian = new Core.Models.Language(globalSettings, "nb-NO");
var english = new Core.Models.Language(globalSettings, "en-GB");
ServiceContext.LocalizationService.Save(norwegian, 0);
ServiceContext.LocalizationService.Save(english, 0);
LocalizationService.Save(norwegian, 0);
LocalizationService.Save(english, 0);
}
private void AssertDictionaryItem(string key, string expectedValue, string cultureCode)
{
Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(key), "DictionaryItem key does not exist");
var dictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey(key);
Assert.That(LocalizationService.DictionaryItemExists(key), "DictionaryItem key does not exist");
var dictionaryItem = LocalizationService.GetDictionaryItemByKey(key);
var translation = dictionaryItem.Translations.SingleOrDefault(i => i.Language.IsoCode == cultureCode);
Assert.IsNotNull(translation, "Translation to {0} was not added", cultureCode);
var value = translation.Value;
@@ -734,9 +766,9 @@ namespace Umbraco.Tests.Packaging
private void AddExistingEnglishParentDictionaryItem(string expectedEnglishParentValue)
{
var languages = ServiceContext.LocalizationService.GetAllLanguages().ToList();
var languages = LocalizationService.GetAllLanguages().ToList();
var englishLanguage = languages.Single(l => l.IsoCode == "en-GB");
ServiceContext.LocalizationService.Save(
LocalizationService.Save(
new DictionaryItem("Parent")
{
Translations = new List<IDictionaryTranslation>
@@ -749,10 +781,10 @@ namespace Umbraco.Tests.Packaging
private void AddExistingEnglishAndNorwegianParentDictionaryItem(string expectedEnglishParentValue, string expectedNorwegianParentValue)
{
var languages = ServiceContext.LocalizationService.GetAllLanguages().ToList();
var languages = LocalizationService.GetAllLanguages().ToList();
var englishLanguage = languages.Single(l => l.IsoCode == "en-GB");
var norwegianLanguage = languages.Single(l => l.IsoCode == "nb-NO");
ServiceContext.LocalizationService.Save(
LocalizationService.Save(
new DictionaryItem("Parent")
{
Translations = new List<IDictionaryTranslation>

View File

@@ -2,74 +2,21 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models.Packaging;
using Umbraco.Core.Packaging;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Integration.Testing;
using Umbraco.Tests.Testing;
namespace Umbraco.Tests.Packaging
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
public class PackageInstallationTest : TestWithDatabaseBase
public class PackageInstallationTest : UmbracoIntegrationTest
{
private DirectoryInfo _testBaseFolder;
public override void SetUp()
{
base.SetUp();
var path = Path.Combine(TestHelper.WorkingDirectory, Guid.NewGuid().ToString());
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
_testBaseFolder = new DirectoryInfo(path);
}
public override void TearDown()
{
base.TearDown();
//clear out files/folders
if (_testBaseFolder.Exists)
_testBaseFolder.Delete(true);
}
private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser(
new ConflictingPackageData(
ServiceContext.MacroService,
ServiceContext.FileService),
Microsoft.Extensions.Options.Options.Create(new GlobalSettings()));
private PackageDataInstallation PackageDataInstallation => new PackageDataInstallation(
NullLoggerFactory.Instance.CreateLogger<PackageDataInstallation>(), NullLoggerFactory.Instance, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService,
ServiceContext.DataTypeService, ServiceContext.EntityService,
ServiceContext.ContentTypeService, ServiceContext.ContentService,
Factory.GetRequiredService<PropertyEditorCollection>(),
Factory.GetRequiredService<IScopeProvider>(),
Factory.GetRequiredService<IShortStringHelper>(),
Microsoft.Extensions.Options.Options.Create(new GlobalSettings()),
Factory.GetRequiredService<ILocalizedTextService>(),
Factory.GetRequiredService<IConfigurationEditorJsonSerializer>(),
Factory.GetRequiredService<IJsonSerializer>()
);
private IPackageInstallation PackageInstallation => new PackageInstallation(
PackageDataInstallation,
new PackageFileInstallation(Parser, IOHelper, HostingEnvironment, ProfilingLogger),
Parser, Mock.Of<IPackageActionRunner>(),
//we don't want to extract package files to the real root, so extract to a test folder
Mock.Of<IHostingEnvironment>(x => x.ApplicationPhysicalPath == _testBaseFolder.FullName));
private IHostingEnvironment HostingEnvironment => GetRequiredService<IHostingEnvironment>();
private IPackageInstallation PackageInstallation => GetRequiredService<IPackageInstallation>();
private const string DocumentTypePickerPackage = "Document_Type_Picker_1.1.umb";
private const string HelloPackage = "Hello_1.0.0.zip";
@@ -79,7 +26,7 @@ namespace Umbraco.Tests.Packaging
{
var package = PackageInstallation.ReadPackage(
//this is where our test zip file is
new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage)));
new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage)));
Assert.IsNotNull(package);
Assert.AreEqual(1, package.Files.Count);
Assert.AreEqual("095e064b-ba4d-442d-9006-3050983c13d8.dll", package.Files[0].UniqueFileName);
@@ -102,7 +49,7 @@ namespace Umbraco.Tests.Packaging
{
var package = PackageInstallation.ReadPackage(
//this is where our test zip file is
new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), HelloPackage)));
new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), HelloPackage)));
Assert.IsNotNull(package);
Assert.AreEqual(0, package.Files.Count);
Assert.AreEqual("Hello", package.Name);
@@ -128,12 +75,12 @@ namespace Umbraco.Tests.Packaging
{
//copy a file to the same path that the package will install so we can detect file conflicts
var filePath = Path.Combine(_testBaseFolder.FullName, "bin", "Auros.DocumentTypePicker.dll");
var filePath = Path.Combine(HostingEnvironment.MapPathContentRoot("~/"), "bin", "Auros.DocumentTypePicker.dll");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
File.WriteAllText(filePath, "test");
//this is where our test zip file is
var packageFile = Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage);
var packageFile = Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage);
Console.WriteLine(packageFile);
var package = PackageInstallation.ReadPackage(new FileInfo(packageFile));
@@ -141,7 +88,7 @@ namespace Umbraco.Tests.Packaging
Assert.IsNotNull(preInstallWarnings);
Assert.AreEqual(1, preInstallWarnings.FilesReplaced.Count());
Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", preInstallWarnings.FilesReplaced.First());
Assert.AreEqual(Path.Combine("bin", "Auros.DocumentTypePicker.dll"), preInstallWarnings.FilesReplaced.First());
// TODO: More Asserts
}
@@ -151,7 +98,7 @@ namespace Umbraco.Tests.Packaging
{
var package = PackageInstallation.ReadPackage(
//this is where our test zip file is
new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage)));
new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage)));
var def = PackageDefinition.FromCompiledPackage(package);
def.Id = 1;
@@ -161,8 +108,8 @@ namespace Umbraco.Tests.Packaging
var result = PackageInstallation.InstallPackageFiles(def, package, -1).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", result[0]);
Assert.IsTrue(File.Exists(Path.Combine(_testBaseFolder.FullName, result[0])));
Assert.AreEqual(Path.Combine("bin", "Auros.DocumentTypePicker.dll"), result[0]);
Assert.IsTrue(File.Exists(Path.Combine(HostingEnvironment.MapPathContentRoot("~/"), result[0])));
//make sure the def is updated too
Assert.AreEqual(result.Count, def.Files.Count);
@@ -173,7 +120,7 @@ namespace Umbraco.Tests.Packaging
{
var package = PackageInstallation.ReadPackage(
//this is where our test zip file is
new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage)));
new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage)));
var def = PackageDefinition.FromCompiledPackage(package);
def.Id = 1;
def.PackageId = Guid.NewGuid();
@@ -186,7 +133,5 @@ namespace Umbraco.Tests.Packaging
//make sure the def is updated too
Assert.AreEqual(summary.DataTypesInstalled.Count(), def.DataTypes.Count);
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -10,10 +10,12 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Net;
using Umbraco.Tests.Common.Builders;
using Umbraco.Tests.Integration.Testing;
using Umbraco.Tests.Testing;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.PublishedCache.NuCache;
namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
{
@@ -510,7 +512,9 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
{
// one simple content type, variant, with both variant and invariant properties
// can change it to invariant and back
GetRequiredService<IPublishedSnapshotService>(); //hack to ensure events are initialized
//hack to ensure events are initialized
(GetRequiredService<IPublishedSnapshotService>() as PublishedSnapshotService)?.OnApplicationInit(null, null);
CreateFrenchAndEnglishLangs();
var contentType = CreateContentType(ContentVariation.Culture);
@@ -599,7 +603,9 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
// one simple content type, invariant
// can change it to variant and back
// can then switch one property to variant
GetRequiredService<IPublishedSnapshotService>(); //hack to ensure events are initialized
//hack to ensure events are initialized
(GetRequiredService<IPublishedSnapshotService>() as PublishedSnapshotService)?.OnApplicationInit(null, null);
var globalSettings = new GlobalSettings();
@@ -690,7 +696,9 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
{
// one simple content type, variant, with both variant and invariant properties
// can change an invariant property to variant and back
GetRequiredService<IPublishedSnapshotService>(); //hack to ensure events are initialized
//hack to ensure events are initialized
(GetRequiredService<IPublishedSnapshotService>() as PublishedSnapshotService)?.OnApplicationInit(null, null);
CreateFrenchAndEnglishLangs();
var contentType = CreateContentType(ContentVariation.Culture);
@@ -967,8 +975,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
// can change the composing content type to invariant and back
// can change the composed content type to invariant and back
GetRequiredService<IPublishedSnapshotService>(); //hack to ensure events are initialized
//hack to ensure events are initialized
(GetRequiredService<IPublishedSnapshotService>() as PublishedSnapshotService)?.OnApplicationInit(null, null);
CreateFrenchAndEnglishLangs();
var composing = CreateContentType(ContentVariation.Culture, "composing");
@@ -1064,7 +1072,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
// can change the composing content type to invariant and back
// can change the variant composed content type to invariant and back
GetRequiredService<IPublishedSnapshotService>(); //hack to ensure events are initialized
//hack to ensure events are initialized
(GetRequiredService<IPublishedSnapshotService>() as PublishedSnapshotService)?.OnApplicationInit(null, null);
CreateFrenchAndEnglishLangs();
var composing = CreateContentType(ContentVariation.Culture, "composing");

View File

@@ -8,7 +8,7 @@ using Umbraco.Core.Services;
using Umbraco.Tests.Common.Builders;
using Umbraco.Tests.Common.Builders.Extensions;
using Umbraco.Tests.Integration.Testing;
using Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing;
using Umbraco.Tests.Services.Importing;
using Umbraco.Tests.Testing;
namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services

View File

@@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing {
namespace Umbraco.Tests.Services.Importing {
using System;
@@ -19,7 +19,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class ImportResources {
@@ -61,6 +61,88 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing {
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;CheckboxListTest&lt;/name&gt;
/// &lt;version&gt;1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;1&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;1&lt;/name&gt;
/// &lt;website&gt;1&lt;/website&gt;
/// &lt;/author&gt;
/// &lt;r [rest of string was truncated]&quot;;.
/// </summary>
internal static string CheckboxList_Content_Package {
get {
return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Compositions Packaged&lt;/name&gt;
/// &lt;version&gt;1.0&lt;/version&gt;
/// &lt;license url=&quot;http://opensource.org/licenses/MIT&quot;&gt;MIT License&lt;/license&gt;
/// &lt;url&gt;http://blog.sitereactor.dk&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Morten Christensen&lt;/name&gt;
/// &lt;website&gt;h [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompositionsTestPackage {
get {
return ResourceManager.GetString("CompositionsTestPackage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Composite Test&lt;/name&gt;
/// &lt;version&gt;dfsfd&lt;/version&gt;
/// &lt;license url=&quot;http://opensource.org/licenses/MIT&quot;&gt;MIT License&lt;/license&gt;
/// &lt;url&gt;ddsff&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;fsdfds&lt;/name&gt;
/// &lt;website&gt;sfdf&lt;/website&gt;
/// &lt;/author&gt;
/// &lt;rea [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompositionsTestPackage_Random {
get {
return ResourceManager.GetString("CompositionsTestPackage_Random", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;umbPackage&gt;
@@ -86,5 +168,243 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing {
return ResourceManager.GetString("Dictionary_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;bootstrap.min.js&lt;/guid&gt;
/// &lt;orgPath&gt;/js&lt;/orgPath&gt;
/// &lt;orgName&gt;bootstrap.min.js&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;jquery.min.js&lt;/guid&gt;
/// &lt;orgPath&gt;/js&lt;/orgPath&gt;
/// &lt;orgName&gt;jquery.min.js&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;top-image.jpg&lt;/guid&gt;
/// &lt;orgPath&gt;/Media/1001&lt;/orgPath&gt;
/// &lt;orgName&gt;top-image.jpg&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;top-im [rest of string was truncated]&quot;;.
/// </summary>
internal static string Fanoe_Package {
get {
return ResourceManager.GetString("Fanoe_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;DocTypeError&lt;/name&gt;
/// &lt;version&gt;1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;Personal license&lt;/license&gt;
/// &lt;url&gt;http://www.iseli-webconsulting.de&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Iseli Webconsulting&lt;/name&gt; [rest of string was truncated]&quot;;.
/// </summary>
internal static string InheritedDocTypes_Package {
get {
return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Package With MediaTypes And Media + Folder&lt;/name&gt;
/// &lt;version&gt;1.0.0&lt;/version&gt;
/// &lt;iconUrl&gt;&lt;/iconUrl&gt;
/// &lt;license url=&quot;http://opensource.org/licenses/MIT&quot;&gt;MIT License&lt;/license&gt;
/// &lt;url&gt;http://www.umbraco.com&lt;/url&gt;
/// &lt;requirements type=&quot;Strict&quot;&gt;
/// &lt;major&gt;0&lt;/major&gt;
/// &lt;minor&gt;5&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name [rest of string was truncated]&quot;;.
/// </summary>
internal static string MediaTypesAndMedia_Package_xml {
get {
return ResourceManager.GetString("MediaTypesAndMedia_Package.xml", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;DocumentType&gt;
/// &lt;Info&gt;
/// &lt;Name&gt;test&lt;/Name&gt;
/// &lt;Alias&gt;test&lt;/Alias&gt;
/// &lt;Icon&gt;folder.gif&lt;/Icon&gt;
/// &lt;Thumbnail&gt;folder.png&lt;/Thumbnail&gt;
/// &lt;Description&gt;
/// &lt;/Description&gt;
/// &lt;AllowAtRoot&gt;False&lt;/AllowAtRoot&gt;
/// &lt;AllowedTemplates&gt;
/// &lt;Template&gt;test&lt;/Template&gt;
/// &lt;/AllowedTemplates&gt;
/// &lt;DefaultTemplate&gt;test&lt;/DefaultTemplate&gt;
/// &lt;/Info&gt;
/// &lt;Structure&gt;
/// &lt;DocumentType&gt;test&lt;/DocumentType&gt;
/// &lt;/Structure&gt;
/// &lt;GenericProperties&gt;
/// &lt;GenericProperty&gt; [rest of string was truncated]&quot;;.
/// </summary>
internal static string SingleDocType {
get {
return ResourceManager.GetString("SingleDocType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;Map.cshtml&lt;/guid&gt;
/// &lt;orgPath&gt;/macroScripts&lt;/orgPath&gt;
/// &lt;orgName&gt;Map.cshtml&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;AccountController.cs&lt;/guid&gt;
/// &lt;orgPath&gt;/App_Code&lt;/orgPath&gt;
/// &lt;orgName&gt;AccountController.cs&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;ContactController.cs&lt;/guid&gt;
/// &lt;orgPath&gt;/App_Code&lt;/orgPath&gt;
/// &lt;orgName&gt;ContactController.cs&lt;/orgName&gt;
/// &lt;/file&gt;
/// [rest of string was truncated]&quot;;.
/// </summary>
internal static string StandardMvc_Package {
get {
return ResourceManager.GetString("StandardMvc_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Template-Update&lt;/name&gt;
/// &lt;version&gt;0.1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;https://our.umbraco.com/projects&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Morten Christensen&lt;/name&gt;
/// [rest of string was truncated]&quot;;.
/// </summary>
internal static string TemplateOnly_Package {
get {
return ResourceManager.GetString("TemplateOnly_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Template-Update&lt;/name&gt;
/// &lt;version&gt;0.1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;https://our.umbraco.com/projects&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Morten Christensen&lt;/name&gt;
/// [rest of string was truncated]&quot;;.
/// </summary>
internal static string TemplateOnly_Updated_Package {
get {
return ResourceManager.GetString("TemplateOnly_Updated_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;uBlogsy.BusinessLogic.dll&lt;/guid&gt;
/// &lt;orgPath&gt;/bin&lt;/orgPath&gt;
/// &lt;orgName&gt;uBlogsy.BusinessLogic.dll&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;uBlogsy.BusinessLogic.pdb&lt;/guid&gt;
/// &lt;orgPath&gt;/bin&lt;/orgPath&gt;
/// &lt;orgName&gt;uBlogsy.BusinessLogic.pdb&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;uBlogsy.Common.dll&lt;/guid&gt;
/// &lt;orgPath&gt;/bin&lt;/orgPath&gt;
/// &lt;orgName&gt;uBlogsy.Common.dll&lt;/orgNam [rest of string was truncated]&quot;;.
/// </summary>
internal static string uBlogsy_Package {
get {
return ResourceManager.GetString("uBlogsy_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;XSLTsearch.xslt&lt;/guid&gt;
/// &lt;orgPath&gt;/xslt&lt;/orgPath&gt;
/// &lt;orgName&gt;XSLTsearch.xslt&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;XSLTsearch.cs&lt;/guid&gt;
/// &lt;orgPath&gt;/App_Code&lt;/orgPath&gt;
/// &lt;orgName&gt;XSLTsearch.cs&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;/files&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;XSLTsearch&lt;/name&gt;
/// &lt;version&gt;3.0.4&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-li [rest of string was truncated]&quot;;.
/// </summary>
internal static string XsltSearch_Package {
get {
return ResourceManager.GetString("XsltSearch_Package", resourceCulture);
}
}
}
}

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -118,7 +118,43 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="InheritedDocTypes_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>InheritedDocTypes-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="StandardMvc_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>StandardMvc-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="uBlogsy_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>uBlogsy-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="XsltSearch_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>XsltSearch-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="SingleDocType" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>SingleDocType.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TemplateOnly_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>TemplateOnly-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TemplateOnly_Updated_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>TemplateOnly-Updated-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CheckboxList_Content_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CheckboxList-Content-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Dictionary_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Dictionary-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CompositionsTestPackage" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CompositionsTestPackage.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CompositionsTestPackage_Random" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CompositionsTestPackage-Random.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Fanoe_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Fanoe-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="MediaTypesAndMedia_Package.xml" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>MediaTypesAndMedia-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<umbPackage>
<files />
<info>
<package>
<name>Package With MediaTypes And Media + Folder</name>
<version>1.0.0</version>
<iconUrl></iconUrl>
<license url="http://opensource.org/licenses/MIT">MIT License</license>
<url>http://www.umbraco.com</url>
<requirements type="Strict">
<major>0</major>
<minor>5</minor>
<patch>0</patch>
</requirements>
</package>
<author>
<name>dteam</name>
<website>http://www.umbraco.com</website>
</author>
<contributors></contributors>
<readme><![CDATA[]]></readme>
</info>
<DocumentTypes />
<MediaTypes>
<MediaType>
<Info>
<Name>Folder</Name>
<Alias>Folder</Alias>
<Icon>icon-folder</Icon>
<Thumbnail>icon-folder</Thumbnail>
<Description />
<AllowAtRoot>True</AllowAtRoot>
</Info>
<Structure>
<MediaType>Folder</MediaType>
<MediaType>Image</MediaType>
<MediaType>File</MediaType>
</Structure>
<GenericProperties />
<Tabs />
</MediaType>
<MediaType>
<Info>
<Name>Image</Name>
<Alias>Image</Alias>
<Icon>icon-picture</Icon>
<Thumbnail>icon-picture</Thumbnail>
<Description />
<AllowAtRoot>True</AllowAtRoot>
</Info>
<Structure />
<GenericProperties>
<GenericProperty>
<Name>Upload image</Name>
<Alias>umbracoFile</Alias>
<Type>Umbraco.ImageCropper</Type>
<Definition>1df9f033-e6d4-451f-b8d2-e0cbc50a836f</Definition>
<Tab>Image</Tab>
<Mandatory>True</Mandatory>
<MandatoryMessage />
<Validation />
<ValidationRegExpMessage />
<LabelOnTop>false</LabelOnTop>
<Description><![CDATA[]]></Description>
</GenericProperty>
<GenericProperty>
<Name>Width</Name>
<Alias>umbracoWidth</Alias>
<Type>Umbraco.Label</Type>
<Definition>8e7f995c-bd81-4627-9932-c40e568ec788</Definition>
<Tab>Image</Tab>
<Mandatory>False</Mandatory>
<MandatoryMessage />
<Validation />
<ValidationRegExpMessage />
<LabelOnTop>false</LabelOnTop>
<Description><![CDATA[in pixels]]></Description>
</GenericProperty>
<GenericProperty>
<Name>Height</Name>
<Alias>umbracoHeight</Alias>
<Type>Umbraco.Label</Type>
<Definition>8e7f995c-bd81-4627-9932-c40e568ec788</Definition>
<Tab>Image</Tab>
<Mandatory>False</Mandatory>
<MandatoryMessage />
<Validation />
<ValidationRegExpMessage />
<LabelOnTop>false</LabelOnTop>
<Description><![CDATA[in pixels]]></Description>
</GenericProperty>
<GenericProperty>
<Name>Size</Name>
<Alias>umbracoBytes</Alias>
<Type>Umbraco.Label</Type>
<Definition>930861bf-e262-4ead-a704-f99453565708</Definition>
<Tab>Image</Tab>
<Mandatory>False</Mandatory>
<MandatoryMessage />
<Validation />
<ValidationRegExpMessage />
<LabelOnTop>false</LabelOnTop>
<Description><![CDATA[in bytes]]></Description>
</GenericProperty>
<GenericProperty>
<Name>Type</Name>
<Alias>umbracoExtension</Alias>
<Type>Umbraco.Label</Type>
<Definition>f0bc4bfb-b499-40d6-ba86-058885a5178c</Definition>
<Tab>Image</Tab>
<Mandatory>False</Mandatory>
<MandatoryMessage />
<Validation />
<ValidationRegExpMessage />
<LabelOnTop>false</LabelOnTop>
<Description><![CDATA[]]></Description>
</GenericProperty>
</GenericProperties>
<Tabs>
<Tab>
<Id>3</Id>
<Caption>Image</Caption>
<SortOrder>1</SortOrder>
</Tab>
</Tabs>
</MediaType>
</MediaTypes>
<Templates />
<Stylesheets />
<Macros />
<DictionaryItems />
<Languages />
<DataTypes />
<MediaItems>
<MediaSet>
<Image id="1145" key="cd4caf13-0705-4e31-9661-48d5a6ce2cc6" parentID="-1" level="1" creatorID="-1" sortOrder="0" createDate="2020-12-15T12:56:46" updateDate="2020-12-15T12:56:46" nodeName="Ledersidetegning Mandag 27 01 20 Rgb (1) (1)" urlName="ledersidetegning-mandag-27-01-20-rgb-1-1" path="-1,1145" isDoc="" nodeType="1032" nodeTypeAlias="Image" writerName="" writerID="0" udi="umb://media/cd4caf1307054e31966148d5a6ce2cc6">
<umbracoFile><![CDATA[{"src":"/media/cwxfztif/ledersidetegning-mandag-27-01-20-rgb-1.jpg","crops":null}]]></umbracoFile>
<umbracoWidth><![CDATA[940]]></umbracoWidth>
<umbracoHeight><![CDATA[564]]></umbracoHeight>
<umbracoBytes><![CDATA[20340]]></umbracoBytes>
<umbracoExtension><![CDATA[jpg]]></umbracoExtension>
</Image>
</MediaSet>
<MediaSet>
<Folder id="1146" key="aef56c09-de35-4d45-b91a-93096dac5e45" parentID="-1" level="1" creatorID="-1" sortOrder="1" createDate="2020-12-15T12:57:26" updateDate="2020-12-15T12:57:26" nodeName="asd" urlName="asd" path="-1,1146" isDoc="" nodeType="1031" nodeTypeAlias="Folder" writerName="" writerID="0" udi="umb://media/aef56c09de354d45b91a93096dac5e45">
<Image id="1147" key="4a3172d8-3c68-4c32-890f-051894e50c8e" parentID="1146" level="2" creatorID="-1" sortOrder="0" createDate="2020-12-15T12:58:00" updateDate="2020-12-15T12:58:00" nodeName="Rider" urlName="rider" path="-1,1146,1147" isDoc="" nodeType="1032" nodeTypeAlias="Image" writerName="" writerID="0" udi="umb://media/4a3172d83c684c32890f051894e50c8e">
<umbracoFile><![CDATA[{"src":"/media/1zzdcsti/rider.png","crops":null}]]></umbracoFile>
<umbracoWidth><![CDATA[839]]></umbracoWidth>
<umbracoHeight><![CDATA[551]]></umbracoHeight>
<umbracoBytes><![CDATA[37605]]></umbracoBytes>
<umbracoExtension><![CDATA[png]]></umbracoExtension>
</Image>
</Folder>
</MediaSet>
</MediaItems>
<Actions />
</umbPackage>

View File

@@ -1,8 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
@@ -31,7 +32,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
[TestFixture]
[Apartment(ApartmentState.STA)]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
public class ThreadSafetyServiceTest : UmbracoIntegrationTest
{
private IContentService ContentService => GetRequiredService<IContentService>();
@@ -98,13 +99,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
if (Environment.GetEnvironmentVariable("UMBRACO_TMP") != null)
Assert.Ignore("Do not run on VSTS.");
var log = GetRequiredService<ILogger<ThreadSafetyServiceTest>>();
// the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton
var contentService = (ContentService)ContentService;
var threads = new List<Thread>();
var exceptions = new List<Exception>();
Debug.WriteLine("Starting...");
log.LogInformation("Starting...");
var done = TraceLocks();
@@ -114,12 +117,12 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
{
try
{
Debug.WriteLine("[{0}] Running...", Thread.CurrentThread.ManagedThreadId);
log.LogInformation("[{0}] Running...", Thread.CurrentThread.ManagedThreadId);
var name1 = "test-" + Guid.NewGuid();
var content1 = contentService.Create(name1, -1, "umbTextpage");
Debug.WriteLine("[{0}] Saving content #1.", Thread.CurrentThread.ManagedThreadId);
log.LogInformation("[{0}] Saving content #1.", Thread.CurrentThread.ManagedThreadId);
Save(contentService, content1);
Thread.Sleep(100); //quick pause for maximum overlap!
@@ -127,7 +130,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
var name2 = "test-" + Guid.NewGuid();
var content2 = contentService.Create(name2, -1, "umbTextpage");
Debug.WriteLine("[{0}] Saving content #2.", Thread.CurrentThread.ManagedThreadId);
log.LogInformation("[{0}] Saving content #2.", Thread.CurrentThread.ManagedThreadId);
Save(contentService, content2);
}
catch (Exception e)
@@ -139,16 +142,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
}
// start all threads
Debug.WriteLine("Starting threads");
log.LogInformation("Starting threads");
threads.ForEach(x => x.Start());
// wait for all to complete
Debug.WriteLine("Joining threads");
log.LogInformation("Joining threads");
threads.ForEach(x => x.Join());
done.Set();
Debug.WriteLine("Checking exceptions");
log.LogInformation("Checking exceptions");
if (exceptions.Count == 0)
{
//now look up all items, there should be 40!
@@ -166,13 +169,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
{
if (Environment.GetEnvironmentVariable("UMBRACO_TMP") != null)
Assert.Ignore("Do not run on VSTS.");
var log = GetRequiredService<ILogger<ThreadSafetyServiceTest>>();
// mimick the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton
var mediaService = (MediaService)MediaService;
var threads = new List<Thread>();
var exceptions = new List<Exception>();
Debug.WriteLine("Starting...");
log.LogInformation("Starting...");
var done = TraceLocks();
@@ -182,18 +188,18 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services
{
try
{
Debug.WriteLine("[{0}] Running...", Thread.CurrentThread.ManagedThreadId);
log.LogInformation("[{0}] Running...", Thread.CurrentThread.ManagedThreadId);
var name1 = "test-" + Guid.NewGuid();
var media1 = mediaService.CreateMedia(name1, -1, Constants.Conventions.MediaTypes.Folder);
Debug.WriteLine("[{0}] Saving media #1.", Thread.CurrentThread.ManagedThreadId);
log.LogInformation("[{0}] Saving media #1.", Thread.CurrentThread.ManagedThreadId);
Save(mediaService, media1);
Thread.Sleep(100); //quick pause for maximum overlap!
var name2 = "test-" + Guid.NewGuid();
var media2 = mediaService.CreateMedia(name2, -1, Constants.Conventions.MediaTypes.Folder);
Debug.WriteLine("[{0}] Saving media #2.", Thread.CurrentThread.ManagedThreadId);
log.LogInformation("[{0}] Saving media #2.", Thread.CurrentThread.ManagedThreadId);
Save(mediaService, media2);
}
catch (Exception e)

View File

@@ -19,6 +19,16 @@
<EmbeddedResource Remove="Views\**" />
<None Remove="Views\**" />
<None Remove="create_slicing_filter_condition.sh" />
<EmbeddedResource Update="Umbraco.Infrastructure\Services\Importing\ImportResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>ImportResources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Update="Umbraco.Infrastructure\Services\Importing\ImportResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ImportResources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
@@ -26,7 +36,22 @@
</ItemGroup>
<ItemGroup>
<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>
@@ -58,20 +83,4 @@
<Folder Include="Umbraco\logs" />
</ItemGroup>
<ItemGroup>
<Compile Update="Umbraco.Infrastructure\Services\Importing\ImportResources.Designer.cs">
<DependentUpon>ImportResources.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Umbraco.Infrastructure\Services\Importing\ImportResources.resx">
<SubType>Designer</SubType>
<LastGenOutput>ImportResources.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -92,6 +92,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache
Assert.AreEqual("one", s1.Get(1));
}
[Retry(5)] // TODO make this test non-flaky.
[Test]
public async Task CollectValues()
{
@@ -218,6 +219,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache
Assert.AreEqual(0, d.Count);
}
[Retry(5)] // TODO make this test non-flaky.
[Test]
public async Task CollectNulls()
{
@@ -527,6 +529,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache
Assert.AreEqual(1, d.Test.GetValues(1).Length);
}
[Retry(5)] // TODO make this test non-flaky.
[Test]
public async Task RandomTest1()
{
@@ -573,6 +576,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache
Assert.AreEqual(0, d.SnapCount);
}
[Retry(5)] // TODO make this test non-flaky.
[Test]
public async Task RandomTest2()
{

View File

@@ -4,11 +4,11 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Extensions.Logging;
using NPoco;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
@@ -28,7 +28,6 @@ using Umbraco.Web.Composing;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Scheduling;
using File = System.IO.File;
using Task = System.Threading.Tasks.Task;
namespace Umbraco.Tests.LegacyXmlPublishedCache
{
@@ -761,7 +760,7 @@ AND (umbracoNode.id=@id)";
// The indenting resumes once the mixed content element is closed." - says MSDN
// about XmlWriterSettings.Indent
// so ImportContent must also make sure of ignoring whitespaces!
// so ImportContentBase must also make sure of ignoring whitespaces!
var sb = new StringBuilder();
using (var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings

View File

@@ -1,383 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Tests.Services.Importing {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class ImportResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ImportResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.Services.Importing.ImportResources", typeof(ImportResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;CheckboxListTest&lt;/name&gt;
/// &lt;version&gt;1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;1&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;1&lt;/name&gt;
/// &lt;website&gt;1&lt;/website&gt;
/// &lt;/author&gt;
/// &lt;r [rest of string was truncated]&quot;;.
/// </summary>
internal static string CheckboxList_Content_Package {
get {
return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Compositions Packaged&lt;/name&gt;
/// &lt;version&gt;1.0&lt;/version&gt;
/// &lt;license url=&quot;http://opensource.org/licenses/MIT&quot;&gt;MIT License&lt;/license&gt;
/// &lt;url&gt;http://blog.sitereactor.dk&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Morten Christensen&lt;/name&gt;
/// &lt;website&gt;h [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompositionsTestPackage {
get {
return ResourceManager.GetString("CompositionsTestPackage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Composite Test&lt;/name&gt;
/// &lt;version&gt;dfsfd&lt;/version&gt;
/// &lt;license url=&quot;http://opensource.org/licenses/MIT&quot;&gt;MIT License&lt;/license&gt;
/// &lt;url&gt;ddsff&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;fsdfds&lt;/name&gt;
/// &lt;website&gt;sfdf&lt;/website&gt;
/// &lt;/author&gt;
/// &lt;rea [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompositionsTestPackage_Random {
get {
return ResourceManager.GetString("CompositionsTestPackage_Random", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Dictionary-Package&lt;/name&gt;
/// &lt;version&gt;1.0&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;http://not.available&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Test&lt;/name&gt;
/// &lt;website&gt;http://not.available&lt;/w [rest of string was truncated]&quot;;.
/// </summary>
internal static string Dictionary_Package {
get {
return ResourceManager.GetString("Dictionary_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;bootstrap.min.js&lt;/guid&gt;
/// &lt;orgPath&gt;/js&lt;/orgPath&gt;
/// &lt;orgName&gt;bootstrap.min.js&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;jquery.min.js&lt;/guid&gt;
/// &lt;orgPath&gt;/js&lt;/orgPath&gt;
/// &lt;orgName&gt;jquery.min.js&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;top-image.jpg&lt;/guid&gt;
/// &lt;orgPath&gt;/Media/1001&lt;/orgPath&gt;
/// &lt;orgName&gt;top-image.jpg&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;top-im [rest of string was truncated]&quot;;.
/// </summary>
internal static string Fanoe_Package {
get {
return ResourceManager.GetString("Fanoe_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;DocTypeError&lt;/name&gt;
/// &lt;version&gt;1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;Personal license&lt;/license&gt;
/// &lt;url&gt;http://www.iseli-webconsulting.de&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Iseli Webconsulting&lt;/name&gt; [rest of string was truncated]&quot;;.
/// </summary>
internal static string InheritedDocTypes_Package {
get {
return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;DocumentType&gt;
/// &lt;Info&gt;
/// &lt;Name&gt;test&lt;/Name&gt;
/// &lt;Alias&gt;test&lt;/Alias&gt;
/// &lt;Icon&gt;folder.gif&lt;/Icon&gt;
/// &lt;Thumbnail&gt;folder.png&lt;/Thumbnail&gt;
/// &lt;Description&gt;
/// &lt;/Description&gt;
/// &lt;AllowAtRoot&gt;False&lt;/AllowAtRoot&gt;
/// &lt;AllowedTemplates&gt;
/// &lt;Template&gt;test&lt;/Template&gt;
/// &lt;/AllowedTemplates&gt;
/// &lt;DefaultTemplate&gt;test&lt;/DefaultTemplate&gt;
/// &lt;/Info&gt;
/// &lt;Structure&gt;
/// &lt;DocumentType&gt;test&lt;/DocumentType&gt;
/// &lt;/Structure&gt;
/// &lt;GenericProperties&gt;
/// &lt;GenericProperty&gt; [rest of string was truncated]&quot;;.
/// </summary>
internal static string SingleDocType {
get {
return ResourceManager.GetString("SingleDocType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;Map.cshtml&lt;/guid&gt;
/// &lt;orgPath&gt;/macroScripts&lt;/orgPath&gt;
/// &lt;orgName&gt;Map.cshtml&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;AccountController.cs&lt;/guid&gt;
/// &lt;orgPath&gt;/App_Code&lt;/orgPath&gt;
/// &lt;orgName&gt;AccountController.cs&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;ContactController.cs&lt;/guid&gt;
/// &lt;orgPath&gt;/App_Code&lt;/orgPath&gt;
/// &lt;orgName&gt;ContactController.cs&lt;/orgName&gt;
/// &lt;/file&gt;
/// [rest of string was truncated]&quot;;.
/// </summary>
internal static string StandardMvc_Package {
get {
return ResourceManager.GetString("StandardMvc_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Template-Update&lt;/name&gt;
/// &lt;version&gt;0.1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;https://our.umbraco.com/projects&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Morten Christensen&lt;/name&gt;
/// [rest of string was truncated]&quot;;.
/// </summary>
internal static string TemplateOnly_Package {
get {
return ResourceManager.GetString("TemplateOnly_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Template-Update&lt;/name&gt;
/// &lt;version&gt;0.1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;https://our.umbraco.com/projects&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;Morten Christensen&lt;/name&gt;
/// [rest of string was truncated]&quot;;.
/// </summary>
internal static string TemplateOnly_Updated_Package {
get {
return ResourceManager.GetString("TemplateOnly_Updated_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;uBlogsy.BusinessLogic.dll&lt;/guid&gt;
/// &lt;orgPath&gt;/bin&lt;/orgPath&gt;
/// &lt;orgName&gt;uBlogsy.BusinessLogic.dll&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;uBlogsy.BusinessLogic.pdb&lt;/guid&gt;
/// &lt;orgPath&gt;/bin&lt;/orgPath&gt;
/// &lt;orgName&gt;uBlogsy.BusinessLogic.pdb&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;uBlogsy.Common.dll&lt;/guid&gt;
/// &lt;orgPath&gt;/bin&lt;/orgPath&gt;
/// &lt;orgName&gt;uBlogsy.Common.dll&lt;/orgNam [rest of string was truncated]&quot;;.
/// </summary>
internal static string uBlogsy_Package {
get {
return ResourceManager.GetString("uBlogsy_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;XSLTsearch.xslt&lt;/guid&gt;
/// &lt;orgPath&gt;/xslt&lt;/orgPath&gt;
/// &lt;orgName&gt;XSLTsearch.xslt&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;XSLTsearch.cs&lt;/guid&gt;
/// &lt;orgPath&gt;/App_Code&lt;/orgPath&gt;
/// &lt;orgName&gt;XSLTsearch.cs&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;/files&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;XSLTsearch&lt;/name&gt;
/// &lt;version&gt;3.0.4&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-li [rest of string was truncated]&quot;;.
/// </summary>
internal static string XsltSearch_Package {
get {
return ResourceManager.GetString("XsltSearch_Package", resourceCulture);
}
}
}
}

View File

@@ -1,157 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="InheritedDocTypes_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>inheriteddoctypes-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="StandardMvc_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>standardmvc-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="uBlogsy_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ublogsy-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="XsltSearch_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>xsltsearch-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="SingleDocType" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>singledoctype.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TemplateOnly_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>templateonly-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TemplateOnly_Updated_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>templateonly-updated-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CheckboxList_Content_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>checkboxlist-content-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Dictionary_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>dictionary-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CompositionsTestPackage" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>compositionstestpackage.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CompositionsTestPackage_Random" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>compositionstestpackage-random.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Fanoe_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>fanoe-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View File

@@ -199,7 +199,6 @@
<Compile Include="PublishedContent\PublishedRouterTests.cs" />
<Compile Include="PublishedContent\RootNodeTests.cs" />
<Compile Include="Scheduling\BackgroundTaskRunnerTests.cs" />
<Compile Include="Packaging\PackageInstallationTest.cs" />
<Compile Include="Cache\PublishedCache\PublishedMediaCacheTests.cs" />
<Compile Include="Models\MediaXmlTest.cs" />
<Compile Include="Persistence\FaultHandling\ConnectionRetryTest.cs" />
@@ -216,12 +215,6 @@
<Compile Include="Routing\ContentFinderByAliasWithDomainsTests.cs" />
<Compile Include="Routing\DomainsAndCulturesTests.cs" />
<Compile Include="Routing\UrlsWithNestedDomains.cs" />
<Compile Include="Packaging\PackageDataInstallationTests.cs" />
<Compile Include="Services\Importing\ImportResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ImportResources.resx</DependentUpon>
</Compile>
<Compile Include="Web\Controllers\PluginControllerAreaTests.cs" />
<Compile Include="TestHelpers\TestWithDatabaseBase.cs" />
<Compile Include="Routing\ContentFinderByAliasTests.cs" />
@@ -269,7 +262,6 @@
<None Include="App.config">
<SubType>Designer</SubType>
</None>
<None Include="Packaging\Packages\Document_Type_Picker_1.1.umb" />
<None Include="UmbracoExamine\TestFiles\umbraco-sort.config">
<SubType>Designer</SubType>
</None>
@@ -309,11 +301,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Services\Importing\ImportResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>ImportResources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="UmbracoExamine\TestFiles.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>TestFiles.Designer.cs</LastGenOutput>
@@ -321,23 +308,8 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="Services\Importing\CheckboxList-Content-Package.xml">
<SubType>Designer</SubType>
</Content>
<Content Include="Services\Importing\CompositionsTestPackage-Random.xml" />
<Content Include="Services\Importing\CompositionsTestPackage.xml" />
<Content Include="Services\Importing\Dictionary-Package.xml" />
<Content Include="Services\Importing\Fanoe-Package.xml" />
<Content Include="UmbracoExamine\TestFiles\media.xml" />
<Content Include="Services\Importing\InheritedDocTypes-Package.xml" />
<Content Include="Services\Importing\SingleDocType.xml" />
<Content Include="Services\Importing\StandardMvc-Package.xml">
<SubType>Designer</SubType>
</Content>
<Content Include="Services\Importing\TemplateOnly-Package.xml" />
<Content Include="Services\Importing\TemplateOnly-Updated-Package.xml" />
<Content Include="Services\Importing\uBlogsy-Package.xml" />
<Content Include="Services\Importing\XsltSearch-Package.xml" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

View File

@@ -127,20 +127,6 @@ namespace Umbraco.Web.BackOffice.Controllers
_logger = loggerFactory.CreateLogger<ContentController>();
_allLangs = new Lazy<IDictionary<string, ILanguage>>(() => _localizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase));
}
/// <summary>
/// Returns true if any content types have culture variation enabled
/// </summary>
/// <returns></returns>
[HttpGet]
// TODO: We need to move this since we are going to delete OverrideAuthorization
[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess), OverrideAuthorization]
public bool AllowsCultureVariation()
{
var contentTypes = _contentTypeService.GetAll();
return contentTypes.Any(contentType => contentType.VariesByCulture());
}
/// <summary>

View File

@@ -11,18 +11,14 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Hosting;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Packaging;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
using Umbraco.Core.Security;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Web.Common.Attributes;
@@ -45,9 +41,7 @@ namespace Umbraco.Web.BackOffice.Controllers
// It would be possible to have something like a ContentTypeInfoController for the GetAllPropertyTypeAliases/GetCount/GetAllowedChildren/etc... actions
private readonly IEntityXmlSerializer _serializer;
private readonly GlobalSettings _globalSettings;
private readonly PropertyEditorCollection _propertyEditors;
private readonly IScopeProvider _scopeProvider;
private readonly IContentTypeService _contentTypeService;
private readonly UmbracoMapper _umbracoMapper;
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
@@ -56,15 +50,10 @@ namespace Umbraco.Web.BackOffice.Controllers
private readonly ILocalizedTextService _localizedTextService;
private readonly IFileService _fileService;
private readonly ILogger<ContentTypeController> _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly IContentService _contentService;
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
private readonly ILocalizationService _LocalizationService;
private readonly IMacroService _macroService;
private readonly IEntityService _entityService;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;
private readonly IJsonSerializer _jsonSerializer;
private readonly PackageDataInstallation _packageDataInstallation;
public ContentTypeController(
ICultureDictionary cultureDictionary,
@@ -74,24 +63,17 @@ namespace Umbraco.Web.BackOffice.Controllers
UmbracoMapper umbracoMapper,
ILocalizedTextService localizedTextService,
IEntityXmlSerializer serializer,
IOptions<GlobalSettings> globalSettings,
PropertyEditorCollection propertyEditors,
IScopeProvider scopeProvider,
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
IDataTypeService dataTypeService,
IShortStringHelper shortStringHelper,
IFileService fileService,
ILogger<ContentTypeController> logger,
ILoggerFactory loggerFactory,
IContentService contentService,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
ILocalizationService localizationService,
IMacroService macroService,
IEntityService entityService,
IHostingEnvironment hostingEnvironment,
EditorValidatorCollection editorValidatorCollection,
IConfigurationEditorJsonSerializer configurationEditorJsonSerializer,
IJsonSerializer jsonSerializer)
PackageDataInstallation packageDataInstallation)
: base(cultureDictionary,
editorValidatorCollection,
contentTypeService,
@@ -101,9 +83,7 @@ namespace Umbraco.Web.BackOffice.Controllers
localizedTextService)
{
_serializer = serializer;
_globalSettings = globalSettings.Value;
_propertyEditors = propertyEditors;
_scopeProvider = scopeProvider;
_contentTypeService = contentTypeService;
_umbracoMapper = umbracoMapper;
_backofficeSecurityAccessor = backofficeSecurityAccessor;
@@ -112,15 +92,10 @@ namespace Umbraco.Web.BackOffice.Controllers
_localizedTextService = localizedTextService;
_fileService = fileService;
_logger = logger;
_loggerFactory = loggerFactory;
_contentService = contentService;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_LocalizationService = localizationService;
_macroService = macroService;
_entityService = entityService;
_hostingEnvironment = hostingEnvironment;
_configurationEditorJsonSerializer = configurationEditorJsonSerializer;
_jsonSerializer = jsonSerializer;
_packageDataInstallation = packageDataInstallation;
}
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
@@ -256,6 +231,19 @@ namespace Umbraco.Web.BackOffice.Controllers
});
return Ok(result);
}
/// <summary>
/// Returns true if any content types have culture variation enabled
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]
public bool AllowsCultureVariation()
{
IEnumerable<IContentType> contentTypes = _contentTypeService.GetAll();
return contentTypes.Any(contentType => contentType.VariesByCulture());
}
/// <summary>
/// Returns where a particular composition has been used
/// This has been wrapped in a dto instead of simple parameters to support having multiple parameters in post request body
@@ -627,30 +615,13 @@ namespace Umbraco.Web.BackOffice.Controllers
return NotFound();
}
var dataInstaller = new PackageDataInstallation(
_loggerFactory.CreateLogger<PackageDataInstallation>(),
_loggerFactory,
_fileService,
_macroService,
_LocalizationService,
_dataTypeService,
_entityService,
_contentTypeService,
_contentService,
_propertyEditors,
_scopeProvider,
_shortStringHelper,
Options.Create(_globalSettings),
_localizedTextService,
_configurationEditorJsonSerializer,
_jsonSerializer);
var xd = new XmlDocument {XmlResolver = null};
xd.Load(filePath);
var userId = _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0);
var element = XElement.Parse(xd.InnerXml);
dataInstaller.ImportDocumentType(element, userId);
_packageDataInstallation.ImportDocumentType(element, userId);
// Try to clean up the temporary file.
try

View File

@@ -479,7 +479,7 @@ namespace Umbraco.Web.BackOffice.Controllers
{
// Authorize...
var requirement = new MediaPermissionsResourceRequirement();
var authorizationResult = await _authorizationService.AuthorizeAsync(User, _mediaService.GetById(move.Id), requirement);
var authorizationResult = await _authorizationService.AuthorizeAsync(User, new MediaPermissionsResource(_mediaService.GetById(move.Id)), requirement);
if (!authorizationResult.Succeeded)
{
return Forbid();

View File

@@ -13,11 +13,9 @@ using Umbraco.Core.Hosting;
using Umbraco.Core.Models.Packaging;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Web.BackOffice.Filters;
using Umbraco.Web.Common.Attributes;
using Umbraco.Web.Common.Authorization;
using Umbraco.Web.Common.Exceptions;
using Umbraco.Web.Security;
namespace Umbraco.Web.BackOffice.Controllers
{
@@ -105,7 +103,7 @@ namespace Umbraco.Web.BackOffice.Controllers
if (package == null)
return NotFound();
var fullPath = _hostingEnvironment.MapPathContentRoot(package.PackagePath);
var fullPath = _hostingEnvironment.MapPathWebRoot(package.PackagePath);
if (!System.IO.File.Exists(fullPath))
throw HttpResponseException.CreateNotificationValidationErrorResponse("No file found for path " + package.PackagePath);

View File

@@ -30,7 +30,6 @@ namespace Umbraco.Extensions
public static IUmbracoBuilder AddBackOffice(this IUmbracoBuilder builder)
{
builder.Services.AddAntiforgery();
builder.Services.AddSingleton<IFilterProvider, OverrideAuthorizationFilterProvider>();
builder.Services
.AddAuthentication() // This just creates a builder, nothing more

View File

@@ -1,25 +0,0 @@
using System;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Umbraco.Web.BackOffice.Filters
{
// TODO: This should probably be deleted, anything requiring this should move to a different controller
public class OverrideAuthorizationAttribute : ActionFilterAttribute
{
/// <summary>
/// Ensures a special type of authorization filter is ignored. Defaults to <see cref="IAuthorizationFilter"/>.
/// </summary>
/// <param name="type">The type of authorization filter to override. if null then <see cref="IAuthorizationFilter"/> is used.</param>
/// <remarks>
/// https://stackoverflow.com/questions/33558095/overrideauthorizationattribute-in-asp-net-5
/// </remarks>
public OverrideAuthorizationAttribute(Type filtersToOverride = null)
{
FiltersToOverride = filtersToOverride ?? typeof(IAuthorizationFilter);
}
public Type FiltersToOverride { get;}
}
}

View File

@@ -1,35 +0,0 @@
using System.Linq;
using Microsoft.AspNetCore.Mvc.Filters;
using Umbraco.Core;
namespace Umbraco.Web.BackOffice.Filters
{
// TODO: This should be deleted, anything requiring this should move to a different controller
public class OverrideAuthorizationFilterProvider : IFilterProvider, IFilterMetadata
{
public void OnProvidersExecuted(FilterProviderContext context)
{
}
public void OnProvidersExecuting(FilterProviderContext context)
{
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
{
//Does the action have any UmbracoAuthorizeFilter?
var overrideFilters = context.Results.Where(filterItem => filterItem.Filter is OverrideAuthorizationAttribute).ToArray();
foreach (var overrideFilter in overrideFilters)
{
context.Results.RemoveAll(filterItem =>
//Remove any filter for the type indicated in the UmbracoAuthorizeFilter attribute
filterItem.Descriptor.Filter.GetType() == ((OverrideAuthorizationAttribute)overrideFilter.Filter).FiltersToOverride &&
//Remove filters with lower scope (ie controller) than the override filter (ie action method)
filterItem.Descriptor.Scope < overrideFilter.Descriptor.Scope);
}
}
}
//all framework providers have negative orders, so ours will come later
public int Order => 1;
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Umbraco.Net;
@@ -21,16 +20,6 @@ namespace Umbraco.Web.Common.AspNetCore
public void Restart()
{
IsRestarting = true;
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext != null)
{
// unload app domain - we must null out all identities otherwise we get serialization errors
// http://www.zpqrtbnk.net/posts/custom-iidentity-serialization-issue
httpContext.User = null;
}
Thread.CurrentPrincipal = null;
_hostApplicationLifetime.StopApplication();
}

View File

@@ -143,11 +143,14 @@ namespace Umbraco.Core.DependencyInjection
builder.Services.AddUnique<IUmbracoDatabase>(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().CreateDatabase());
builder.Services.AddUnique<ISqlContext>(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().SqlContext);
builder.Services.AddUnique<IUmbracoVersion, UmbracoVersion>();
builder.Services.AddUnique<IRuntime, CoreRuntime>();
builder.Services.AddUnique<IRuntimeState, RuntimeState>();
builder.Services.AddUnique<IHostingEnvironment, AspNetCoreHostingEnvironment>();
builder.Services.AddUnique<IMainDom, MainDom>();
builder.Services.AddUnique<IRuntime, CoreRuntime>();
builder.Services.AddHostedService<IRuntime>(factory => factory.GetRequiredService<IRuntime>());
builder.AddCoreInitialServices();
builder.AddComposers();
return builder;

View File

@@ -2,7 +2,6 @@ using System;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Serilog.Context;
using SixLabors.ImageSharp.Web.DependencyInjection;
@@ -11,7 +10,6 @@ using Smidge.Nuglify;
using StackExchange.Profiling;
using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
using Umbraco.Web.Common.Middleware;
using Umbraco.Web.Common.Plugins;
@@ -74,10 +72,10 @@ namespace Umbraco.Extensions
/// </summary>
public static bool UmbracoCanBoot(this IApplicationBuilder app)
{
IRuntime runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
var state = app.ApplicationServices.GetRequiredService<IRuntimeState>();
// can't continue if boot failed
return runtime.State.Level > RuntimeLevel.BootFailed;
return state.Level > RuntimeLevel.BootFailed;
}
/// <summary>
@@ -95,25 +93,10 @@ namespace Umbraco.Extensions
return app;
}
IHostingEnvironment hostingEnvironment = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
AppDomain.CurrentDomain.SetData("DataDirectory", hostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data));
IRuntime runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
// Register a listener for application shutdown in order to terminate the runtime
IApplicationShutdownRegistry hostLifetime = app.ApplicationServices.GetRequiredService<IApplicationShutdownRegistry>();
var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
hostLifetime.RegisterObject(runtimeShutdown);
// Register our global threadabort enricher for logging
ThreadAbortExceptionEnricher threadAbortEnricher = app.ApplicationServices.GetRequiredService<ThreadAbortExceptionEnricher>();
LogContext.Push(threadAbortEnricher); // NOTE: We are not in a using clause because we are not removing it, it is on the global context
StaticApplicationLogging.Initialize(app.ApplicationServices.GetRequiredService<ILoggerFactory>());
// Start the runtime!
runtime.Start();
return app;
}
@@ -204,33 +187,6 @@ namespace Umbraco.Extensions
return app;
}
/// <summary>
/// Ensures the runtime is shutdown when the application is shutting down
/// </summary>
private class CoreRuntimeShutdown : IRegisteredObject
{
public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime)
{
_runtime = runtime;
_hostLifetime = hostLifetime;
}
private bool _completed = false;
private readonly IRuntime _runtime;
private readonly IApplicationShutdownRegistry _hostLifetime;
public void Stop(bool immediate)
{
if (!_completed)
{
_completed = true;
_runtime.Terminate();
_hostLifetime.UnregisterObject(this);
}
}
}
}
}

View File

@@ -1,22 +1,17 @@
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.DependencyInjection;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Diagnostics;
using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
using Umbraco.Core.Runtime;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Extensions;
using Umbraco.Net;
using Umbraco.Web.Common.AspNetCore;
using Umbraco.Web.Common.Controllers;
using Umbraco.Web.Common.Formatters;
using Umbraco.Web.Common.Install;
using Umbraco.Web.Common.Lifetime;
using Umbraco.Web.Common.Macros;
@@ -38,7 +33,6 @@ namespace Umbraco.Web.Common.Runtime
/// Adds/replaces AspNetCore specific services
/// </summary>
[ComposeBefore(typeof(ICoreComposer))]
[ComposeAfter(typeof(CoreInitialComposer))]
public class AspNetCoreComposer : ComponentComposer<AspNetCoreComponent>, IComposer
{
public override void Compose(IUmbracoBuilder builder)

View File

@@ -42,16 +42,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
return {
allowsCultureVariation: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"AllowsCultureVariation")),
'Failed to retrieve variant content types');
},
savePermissions: function (saveModel) {
savePermissions: function (saveModel) {
if (!saveModel) {
throw "saveModel cannot be null";
}

View File

@@ -361,6 +361,15 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
"HasContentNodes",
[{ id: id }])),
'Failed to retrieve indication for whether content type with id ' + id + ' has associated content nodes');
},
allowsCultureVariation: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentTypeApiBaseUrl",
"AllowsCultureVariation")),
'Failed to retrieve variant content types');
}
};
}

View File

@@ -9,7 +9,7 @@
*
* @param {navigationService} navigationService A reference to the navigationService
*/
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource, editorState) {
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentTypeResource, editorState) {
//this is used to trigger the tree to start loading once everything is ready
var treeInitPromise = $q.defer();
@@ -380,7 +380,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
*/
function loadLanguages() {
return contentResource.allowsCultureVariation().then(function (b) {
return contentTypeResource.allowsCultureVariation().then(function (b) {
if (b === true) {
return languageResource.getAll();
} else {

View File

@@ -16,6 +16,7 @@
vm.filesOpen = true;
vm.actionsOpen = true;
vm.loading = true;
vm.mediaNodeDisplayModels = [];
vm.back = back;
vm.createOrUpdatePackage = createOrUpdatePackage;
vm.removeContentItem = removeContentItem;
@@ -28,6 +29,7 @@
vm.contributorsEditor = null;
vm.selectDocumentType = selectDocumentType;
vm.selectMediaType = selectMediaType;
vm.selectTemplate = selectTemplate;
vm.selectStyleSheet = selectStyleSheet;
vm.selectMacro = selectMacro;
@@ -35,6 +37,15 @@
vm.selectDictionaryItem = selectDictionaryItem;
vm.selectDataType = selectDataType;
vm.mediaPickerModel = {
hideLabel: true,
view: "mediapicker",
value: "",
config: {
multiPicker: true,
allowEdit:false
}
}
vm.labels = {};
vm.versionRegex = /^(\d+\.)(\d+\.)(\*|\d+)$/;
@@ -76,6 +87,7 @@
});
}
vm.mediaPickerModel.value = vm.package.mediaUdis.join(',');
});
@@ -88,20 +100,31 @@
function loadResources() {
// Get all document types
entityResource.getAll("DocumentType").then(documentTypes => {
// a package stores the id as a string so we
// need to convert all ids to string for comparison
documentTypes.forEach(documentType => {
documentType.id = documentType.id.toString();
documentType.selected = vm.package.documentTypes.indexOf(documentType.id) !== -1;
});
vm.documentTypes = documentTypes;
// Get all document types
entityResource.getAll("DocumentType").then(documentTypes => {
// a package stores the id as a string so we
// need to convert all ids to string for comparison
documentTypes.forEach(documentType => {
documentType.id = documentType.id.toString();
documentType.selected = vm.package.documentTypes.indexOf(documentType.id) !== -1;
});
vm.documentTypes = documentTypes;
});
// Get all media types
entityResource.getAll("MediaType").then(mediaTypes => {
// a package stores the id as a string so we
// need to convert all ids to string for comparison
mediaTypes.forEach(mediaType => {
mediaType.id = mediaType.id.toString();
mediaType.selected = vm.package.mediaTypes.indexOf(mediaType.id) !== -1;
});
vm.mediaTypes = mediaTypes;
});
// Get all templates
entityResource.getAll("Template").then(templates => {
// a package stores the id as a string so we
// a package stores the id as a string so we
// need to convert all ids to string for comparison
templates.forEach(template => {
template.id = template.id.toString();
@@ -120,7 +143,7 @@
// Get all macros
entityResource.getAll("Macro").then(macros => {
// a package stores the id as a string so we
// a package stores the id as a string so we
// need to convert all ids to string for comparison
macros.forEach(macro => {
macro.id = macro.id.toString();
@@ -131,7 +154,7 @@
// Get all languages
entityResource.getAll("Language").then(languages => {
// a package stores the id as a string so we
// a package stores the id as a string so we
// need to convert all ids to string for comparison
languages.forEach(language => {
language.id = language.id.toString();
@@ -142,7 +165,7 @@
// Get all dictionary items
entityResource.getAll("DictionaryItem").then(dictionaryItems => {
// a package stores the id as a string so we
// a package stores the id as a string so we
// need to convert all ids to string for comparison
dictionaryItems.forEach(dictionaryItem => {
dictionaryItem.id = dictionaryItem.id.toString();
@@ -153,7 +176,7 @@
// Get all data types
entityResource.getAll("DataType").then(dataTypes => {
// a package stores the id as a string so we
// a package stores the id as a string so we
// need to convert all ids to string for comparison
dataTypes.forEach(dataType => {
dataType.id = dataType.id.toString();
@@ -181,10 +204,12 @@
function createOrUpdatePackage(editPackageForm) {
let contributors = vm.contributorsEditor.value.map(o => o.value);
let contributors = vm.contributorsEditor.value.map(o => o.value)
vm.package.contributors = contributors;
// Split by comma and remove empty entries
vm.package.mediaUdis = vm.mediaPickerModel.value.split(",").filter(i => i);
if (formHelper.submitForm({ formCtrl: editPackageForm, scope: $scope })) {
vm.buttonState = "busy";
@@ -215,23 +240,23 @@
vm.package.contentNodeId = null;
}
function openContentPicker() {
const contentPicker = {
submit: function (model) {
if (model.selection && model.selection.length > 0) {
vm.package.contentNodeId = model.selection[0].id.toString();
vm.contentNodeDisplayModel = model.selection[0];
}
editorService.close();
},
close: function () {
editorService.close();
}
};
editorService.contentPicker(contentPicker);
}
function openContentPicker() {
const contentPicker = {
submit: function (model) {
if (model.selection && model.selection.length > 0) {
vm.package.contentNodeId = model.selection[0].id.toString();
vm.contentNodeDisplayModel = model.selection[0];
}
editorService.close();
},
close: function () {
editorService.close();
}
};
editorService.contentPicker(contentPicker);
}
function openFilePicker() {
function openFilePicker() {
let selection = Utilities.copy(vm.package.files);
@@ -313,6 +338,18 @@
}
}
function selectMediaType(mediatype) {
// Check if the document type is already selected.
var index = vm.package.mediaTypes.indexOf(mediatype.id);
if (index === -1) {
vm.package.mediaTypes.push(mediatype.id);
} else {
vm.package.mediaTypes.splice(index, 1);
}
}
function selectTemplate(template) {
// Check if the template is already selected.

View File

@@ -137,6 +137,22 @@
</umb-control-group>
<umb-control-group label="@general_media">
<umb-property property="vm.mediaPickerModel" ng-if="vm.loading === false">
<umb-property-editor model="vm.mediaPickerModel" is-pre-value="true"></umb-property-editor>
</umb-property>
<umb-checkbox model="vm.package.mediaLoadChildNodes"
disabled="vm.mediaPickerModel.value.length === 0"
text="{{vm.labels.includeAllChildNodes}}">
</umb-checkbox>
</umb-control-group>
<umb-control-group label="@treeHeaders_documentTypes">
<div ng-repeat="doctype in ::vm.documentTypes | orderBy:'name'">
<umb-checkbox model="doctype.selected"
@@ -146,11 +162,20 @@
</div>
</umb-control-group>
<umb-control-group label="@treeHeaders_mediaTypes">
<div ng-repeat="mediatype in ::vm.mediaTypes | orderBy:'name'">
<umb-checkbox model="mediatype.selected"
on-change="vm.selectMediaType(mediatype)"
text="{{mediatype.name}}">
</umb-checkbox>
</div>
</umb-control-group>
<umb-control-group label="@treeHeaders_templates">
<div ng-repeat="template in ::vm.templates | orderBy:'name'">
<umb-checkbox model="template.selected"
on-change="vm.selectTemplate(template)"
text="{{template.name}}">
text="{{template.name}}">umb-expansion-panel__content
</umb-checkbox>
</div>
</umb-control-group>

View File

@@ -20,7 +20,6 @@ namespace Umbraco.Web.UI.NetCore
{
x.ClearProviders();
})
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
.UseUmbraco();
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
}

View File

@@ -22,6 +22,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="App_Plugins" />
<Folder Include="scripts" />
<Folder Include="umbraco\MediaCache\2\c\6\9\3\a\6\5" />
<Folder Include="umbraco\MediaCache\a\e\e\1\9\e\4\b" />

View File

@@ -730,6 +730,7 @@
<key alias="logout">Logout</key>
<key alias="macro">Macro</key>
<key alias="mandatory">Mandatory</key>
<key alias="media">Media</key>
<key alias="message">Message</key>
<key alias="move">Move</key>
<key alias="name">Name</key>

View File

@@ -1,26 +1,19 @@
using System.Web.Mvc;
using System.Web.Security;
using Microsoft.AspNet.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Core;
using Umbraco.Core.DependencyInjection;
using Umbraco.Core.Composing;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Templates;
using Umbraco.Core.Runtime;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Web.Composing.CompositionExtensions;
using Umbraco.Web.Macros;
using Umbraco.Web.Mvc;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Security;
using Umbraco.Web.Security.Providers;
namespace Umbraco.Web.Runtime
{
// web's initial composer composes after core's, and before all core composers
[ComposeAfter(typeof(CoreInitialComposer))]
[ComposeBefore(typeof(ICoreComposer))]
public sealed class WebInitialComposer : ComponentComposer<WebInitialComponent>
{

View File

@@ -141,8 +141,6 @@
<Compile Include="Mvc\RenderMvcController.cs" />
<Compile Include="Mvc\UmbracoViewPageOfTModel.cs" />
<Compile Include="Security\BackOfficeSecurity.cs" />
<Compile Include="WebApi\Filters\EnableOverrideAuthorizationAttribute.cs" />
<Compile Include="WebApi\Filters\OverridableAuthorizationAttribute.cs" />
<Compile Include="HttpContextAccessorExtensions.cs" />
<Compile Include="Models\Membership\UmbracoMembershipMember.cs" />
<Compile Include="Mvc\HttpUmbracoFormRouteStringException.cs" />

View File

@@ -46,7 +46,6 @@ namespace Umbraco.Web
protected UmbracoApplicationBase()
{
HostingSettings hostingSettings = null;
GlobalSettings globalSettings = null;
SecuritySettings securitySettings = null;
@@ -60,8 +59,6 @@ namespace Umbraco.Web
var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, _loggerFactory.CreateLogger<AspNetBackOfficeInfo>(), Options.Create(webRoutingSettings));
var profiler = GetWebProfiler(hostingEnvironment);
StaticApplicationLogging.Initialize(_loggerFactory);
Logger = NullLogger<UmbracoApplicationBase>.Instance;
}
private IProfiler GetWebProfiler(IHostingEnvironment hostingEnvironment)
@@ -87,7 +84,6 @@ namespace Umbraco.Web
_loggerFactory = loggerFactory;
Logger = logger;
StaticApplicationLogging.Initialize(_loggerFactory);
}
protected ILogger<UmbracoApplicationBase> Logger { get; }
@@ -189,7 +185,6 @@ namespace Umbraco.Web
LogContext.Push(new HttpRequestIdEnricher(_factory.GetRequiredService<IRequestCache>()));
_runtime = _factory.GetRequiredService<IRuntime>();
_runtime.Start();
}
// called by ASP.NET (auto event wireup) once per app domain
@@ -237,7 +232,6 @@ namespace Umbraco.Web
{
if (_runtime != null)
{
_runtime.Terminate();
_runtime.DisposeIfDisposable();
_runtime = null;

View File

@@ -1,16 +0,0 @@
using System;
namespace Umbraco.Web.WebApi.Filters
{
/// <summary>
/// This allows for Action based auth attributes to override Class based auth attributes if they are specified
/// </summary>
/// <remarks>
/// This attribute can be applied at the class level and will indicate to any class level auth attribute that inherits from OverridableAuthorizationAttribute
/// </remarks>
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public sealed class EnableOverrideAuthorizationAttribute : Attribute
{
// TODO: we should remove this and use the System.Web.Http.OverrideAuthorizationAttribute which uses IOverrideFilter instead
}
}

View File

@@ -1,52 +0,0 @@
using System;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Controllers;
namespace Umbraco.Web.WebApi.Filters
{
// TODO: remove this since we don't need it, see notes in EnableOverrideAuthorizationAttribute
/// <summary>
/// Abstract auth filter class that can be used to enable overriding class auth filters at the action level
/// </summary>
/// <remarks>
/// To enable a class auth filter to be overridden by an action auth filter the EnableOverrideAuthorizationAttribute can be applied
/// to the class.
/// </remarks>
public abstract class OverridableAuthorizationAttribute : AuthorizeAttribute
{
/// <summary>
/// If the controller has an EnabledOverrideAuthorizationAttribute attribute specified and the action has any AuthorizeAttribute
/// specified then use the action's auth attribute instead of this one
/// </summary>
/// <param name="actionContext">The context.</param>
/// <exception cref="T:System.ArgumentNullException">The context parameter is null.</exception>
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null) throw new ArgumentNullException("actionContext");
var actionAttributes = actionContext.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>();
//if 'this' authorize attribute exists in the current collection then continue as per normal... this is because 'this' attribute instance
// is obviously assigned at an Action level and therefore it's already executing
if (actionAttributes.Any(x => Equals(x, this)))
{
base.OnAuthorization(actionContext);
return;
}
//if the controller is allowing authorization to be overridden at the action level and there are action level authorization attributes
// then exit and let the action level auth attribute(s) execute.
if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<EnableOverrideAuthorizationAttribute>().Any()
&& actionAttributes.Any())
{
return;
}
base.OnAuthorization(actionContext);
}
}
}